2 * empathy-account.c - Source for EmpathyAccount
3 * Copyright (C) 2009 Collabora Ltd.
4 * @author Sjoerd Simons <sjoerd.simons@collabora.co.uk>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
25 #include <telepathy-glib/enums.h>
26 #include <telepathy-glib/dbus.h>
27 #include <telepathy-glib/account.h>
28 #include <telepathy-glib/gtypes.h>
29 #include <telepathy-glib/util.h>
31 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
32 #include <libempathy/empathy-debug.h>
34 #include "empathy-account.h"
35 #include "empathy-utils.h"
36 #include "empathy-marshal.h"
38 #define UNIQUE_NAME_PREFIX "/org/freedesktop/Telepathy/Account/"
47 static guint signals[LAST_SIGNAL];
54 PROP_CONNECTION_STATUS,
55 PROP_CONNECTION_STATUS_REASON,
62 G_DEFINE_TYPE(EmpathyAccount, empathy_account, G_TYPE_OBJECT)
64 /* private structure */
65 typedef struct _EmpathyAccountPriv EmpathyAccountPriv;
67 struct _EmpathyAccountPriv
69 gboolean dispose_has_run;
71 TpConnection *connection;
72 guint connection_invalidated_id;
74 TpConnectionStatus status;
75 TpConnectionStatusReason reason;
76 TpConnectionPresenceType presence;
81 /* Timestamp when the connection got connected in seconds since the epoch */
93 GHashTable *parameters;
96 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccount)
98 static void _empathy_account_set_connection (EmpathyAccount *account,
99 TpConnection *connection);
102 empathy_account_init (EmpathyAccount *obj)
104 EmpathyAccountPriv *priv;
106 priv = G_TYPE_INSTANCE_GET_PRIVATE (obj,
107 EMPATHY_TYPE_ACCOUNT, EmpathyAccountPriv);
111 priv->status = TP_CONNECTION_STATUS_DISCONNECTED;
115 empathy_account_set_property (GObject *object,
120 EmpathyAccount *account = EMPATHY_ACCOUNT (object);
121 EmpathyAccountPriv *priv = GET_PRIV (account);
126 empathy_account_set_enabled (account, g_value_get_boolean (value));
128 case PROP_UNIQUE_NAME:
129 priv->unique_name = g_value_dup_string (value);
131 case PROP_DBUS_DAEMON:
132 priv->dbus = g_value_get_object (value);
135 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
141 empathy_account_get_property (GObject *object,
146 EmpathyAccount *account = EMPATHY_ACCOUNT (object);
147 EmpathyAccountPriv *priv = GET_PRIV (account);
152 g_value_set_boolean (value, priv->enabled);
155 g_value_set_boolean (value, priv->enabled);
158 g_value_set_uint (value, priv->presence);
160 case PROP_CONNECTION_STATUS:
161 g_value_set_uint (value, priv->status);
163 case PROP_CONNECTION_STATUS_REASON:
164 g_value_set_uint (value, priv->reason);
166 case PROP_CONNECTION:
167 g_value_set_object (value,
168 empathy_account_get_connection (account));
170 case PROP_UNIQUE_NAME:
171 g_value_set_string (value,
172 empathy_account_get_unique_name (account));
174 case PROP_DISPLAY_NAME:
175 g_value_set_string (value,
176 empathy_account_get_display_name (account));
178 case PROP_DBUS_DAEMON:
179 g_value_set_string (value,
180 empathy_account_get_display_name (account));
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
189 empathy_account_update (EmpathyAccount *account, GHashTable *properties)
191 EmpathyAccountPriv *priv = GET_PRIV (account);
192 const gchar *conn_path;
194 TpConnectionStatus old_s = priv->status;
195 TpConnectionPresenceType old_p = priv->presence;
197 if (g_hash_table_lookup (properties, "ConnectionStatus") != NULL)
198 priv->status = tp_asv_get_int32 (properties, "ConnectionStatus", NULL);
200 if (g_hash_table_lookup (properties, "ConnectionStatusReason") != NULL)
201 priv->reason = tp_asv_get_int32 (properties,
202 "ConnectionStatusReason", NULL);
204 if (g_hash_table_lookup (properties, "CurrentPresence") != NULL)
206 arr = tp_asv_get_boxed (properties, "CurrentPresence",
207 TP_STRUCT_TYPE_SIMPLE_PRESENCE);
208 priv->presence = g_value_get_uint (g_value_array_get_nth (arr, 0));
211 if (g_hash_table_lookup (properties, "DisplayName") != NULL)
213 g_strdup (tp_asv_get_string (properties, "DisplayName"));
215 if (g_hash_table_lookup (properties, "Enabled") != NULL)
216 empathy_account_set_enabled (account,
217 tp_asv_get_boolean (properties, "Enabled", NULL));
219 if (g_hash_table_lookup (properties, "Valid") != NULL)
220 priv->valid = tp_asv_get_boolean (properties, "Valid", NULL);
222 if (g_hash_table_lookup (properties, "Parameters") != NULL)
224 GHashTable *parameters;
226 parameters = tp_asv_get_boxed (properties, "Parameters",
227 TP_HASH_TYPE_STRING_VARIANT_MAP);
229 priv->parameters = g_boxed_copy (TP_HASH_TYPE_STRING_VARIANT_MAP,
236 g_object_notify (G_OBJECT (account), "ready");
239 if (priv->status != old_s)
241 if (priv->status == TP_CONNECTION_STATUS_CONNECTED)
244 g_get_current_time (&val);
246 priv->connect_time = val.tv_sec;
249 g_signal_emit (account, signals[STATUS_CHANGED], 0,
250 old_s, priv->status, priv->reason);
252 g_object_notify (G_OBJECT (account), "status");
255 if (priv->presence != old_p)
257 g_signal_emit (account, signals[PRESENCE_CHANGED], 0,
258 old_p, priv->presence);
259 g_object_notify (G_OBJECT (account), "presence");
262 if (g_hash_table_lookup (properties, "Connection") != NULL)
264 conn_path = tp_asv_get_object_path (properties, "Connection");
266 if (tp_strdiff (conn_path, "/") && priv->connection == NULL)
269 GError *error = NULL;
270 conn = tp_connection_new (priv->dbus, NULL, conn_path, &error);
274 DEBUG ("Failed to create a new TpConnection: %s",
276 g_error_free (error);
279 _empathy_account_set_connection (account, conn);
285 empathy_account_properties_changed (TpAccount *proxy,
286 GHashTable *properties,
288 GObject *weak_object)
290 EmpathyAccount *account = EMPATHY_ACCOUNT (weak_object);
291 EmpathyAccountPriv *priv = GET_PRIV (account);
296 empathy_account_update (account, properties);
300 empathy_account_got_all_cb (TpProxy *proxy,
301 GHashTable *properties,
304 GObject *weak_object)
306 EmpathyAccount *account = EMPATHY_ACCOUNT (weak_object);
310 printf ("Unhappy\n");
314 empathy_account_update (account, properties);
318 empathy_account_parse_unique_name (const gchar *bus_name,
319 gchar **protocol, gchar **manager)
321 const gchar *proto, *proto_end;
322 const gchar *cm, *cm_end;
324 g_return_val_if_fail (
325 g_str_has_prefix (bus_name, UNIQUE_NAME_PREFIX), FALSE);
327 cm = bus_name + strlen (UNIQUE_NAME_PREFIX);
329 for (cm_end = cm; *cm_end != '/' && *cm_end != '\0'; cm_end++)
340 for (proto_end = proto; *proto_end != '/' && *proto_end != '\0'; proto_end++)
343 if (*proto_end == '\0')
346 if (protocol != NULL)
347 *protocol = g_strndup (proto, proto_end - proto);
350 *manager = g_strndup (cm, cm_end - cm);
356 empathy_account_constructed (GObject *object)
358 EmpathyAccount *account = EMPATHY_ACCOUNT (object);
359 EmpathyAccountPriv *priv = GET_PRIV (account);
361 priv->account = tp_account_new (priv->dbus, priv->unique_name, NULL);
363 empathy_account_parse_unique_name (priv->unique_name,
364 &(priv->proto_name), &(priv->cm_name));
366 priv->icon_name = g_strdup_printf ("im-%s", priv->proto_name);
368 tp_cli_account_connect_to_account_property_changed (priv->account,
369 empathy_account_properties_changed,
370 NULL, NULL, object, NULL);
372 tp_cli_dbus_properties_call_get_all (priv->account, -1,
374 empathy_account_got_all_cb,
380 static void empathy_account_dispose (GObject *object);
381 static void empathy_account_finalize (GObject *object);
384 empathy_account_class_init (EmpathyAccountClass *empathy_account_class)
386 GObjectClass *object_class = G_OBJECT_CLASS (empathy_account_class);
388 g_type_class_add_private (empathy_account_class,
389 sizeof (EmpathyAccountPriv));
391 object_class->set_property = empathy_account_set_property;
392 object_class->get_property = empathy_account_get_property;
393 object_class->dispose = empathy_account_dispose;
394 object_class->finalize = empathy_account_finalize;
395 object_class->constructed = empathy_account_constructed;
397 g_object_class_install_property (object_class, PROP_ENABLED,
398 g_param_spec_boolean ("enabled",
400 "Whether this account is enabled or not",
402 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE));
404 g_object_class_install_property (object_class, PROP_READY,
405 g_param_spec_boolean ("ready",
407 "Whether this account is ready to be used",
409 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
411 g_object_class_install_property (object_class, PROP_PRESENCE,
412 g_param_spec_uint ("presence",
414 "The account connections presence type",
416 NUM_TP_CONNECTION_PRESENCE_TYPES,
417 TP_CONNECTION_PRESENCE_TYPE_UNSET,
418 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
420 g_object_class_install_property (object_class, PROP_CONNECTION_STATUS,
421 g_param_spec_uint ("status",
423 "The accounts connections status type",
425 NUM_TP_CONNECTION_STATUSES,
426 TP_CONNECTION_STATUS_DISCONNECTED,
427 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
429 g_object_class_install_property (object_class, PROP_CONNECTION_STATUS_REASON,
430 g_param_spec_uint ("status-reason",
431 "ConnectionStatusReason",
432 "The account connections status reason",
434 NUM_TP_CONNECTION_STATUS_REASONS,
435 TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
436 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
438 g_object_class_install_property (object_class, PROP_CONNECTION,
439 g_param_spec_object ("connection",
441 "The accounts connection",
443 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
445 g_object_class_install_property (object_class, PROP_UNIQUE_NAME,
446 g_param_spec_string ("unique-name",
448 "The accounts unique name",
450 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
452 g_object_class_install_property (object_class, PROP_DBUS_DAEMON,
453 g_param_spec_object ("dbus-daemon",
455 "The Tp Dbus daemon on which this account exists",
457 G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
459 g_object_class_install_property (object_class, PROP_DISPLAY_NAME,
460 g_param_spec_string ("display-name",
462 "The accounts display name",
464 G_PARAM_STATIC_STRINGS | G_PARAM_READABLE));
466 signals[STATUS_CHANGED] = g_signal_new ("status-changed",
467 G_TYPE_FROM_CLASS (object_class),
470 _empathy_marshal_VOID__UINT_UINT_UINT,
471 G_TYPE_NONE, 3, G_TYPE_UINT, G_TYPE_UINT, G_TYPE_UINT);
473 signals[PRESENCE_CHANGED] = g_signal_new ("presence-changed",
474 G_TYPE_FROM_CLASS (object_class),
477 _empathy_marshal_VOID__UINT_UINT,
478 G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
482 empathy_account_dispose (GObject *object)
484 EmpathyAccount *self = EMPATHY_ACCOUNT (object);
485 EmpathyAccountPriv *priv = GET_PRIV (self);
487 if (priv->dispose_has_run)
490 priv->dispose_has_run = TRUE;
492 if (priv->connection_invalidated_id != 0)
493 g_signal_handler_disconnect (priv->connection,
494 priv->connection_invalidated_id);
495 priv->connection_invalidated_id = 0;
497 if (priv->connection != NULL)
498 g_object_unref (priv->connection);
499 priv->connection = NULL;
501 /* release any references held by the object here */
502 if (G_OBJECT_CLASS (empathy_account_parent_class)->dispose != NULL)
503 G_OBJECT_CLASS (empathy_account_parent_class)->dispose (object);
507 empathy_account_finalize (GObject *object)
509 EmpathyAccountPriv *priv = GET_PRIV (object);
511 g_free (priv->cm_name);
512 g_free (priv->proto_name);
513 g_free (priv->icon_name);
514 g_free (priv->display_name);
516 /* free any data held directly by the object here */
517 if (G_OBJECT_CLASS (empathy_account_parent_class)->finalize != NULL)
518 G_OBJECT_CLASS (empathy_account_parent_class)->finalize (object);
522 empathy_account_is_just_connected (EmpathyAccount *account)
524 EmpathyAccountPriv *priv = GET_PRIV (account);
527 if (priv->status != TP_CONNECTION_STATUS_CONNECTED)
530 g_get_current_time (&val);
532 return (val.tv_sec - priv->connect_time) < 10;
536 * empathy_account_get_connection:
537 * @account: a #EmpathyAccount
539 * Get the connection of the account, or NULL if account is offline or the
540 * connection is not yet ready. This function does not return a new ref.
542 * Returns: the connection of the account.
545 empathy_account_get_connection (EmpathyAccount *account)
547 EmpathyAccountPriv *priv = GET_PRIV (account);
549 if (priv->connection != NULL &&
550 tp_connection_is_ready (priv->connection))
551 return priv->connection;
557 * empathy_account_get_unique_name:
558 * @account: a #EmpathyAccount
560 * Returns: the unique name of the account.
563 empathy_account_get_unique_name (EmpathyAccount *account)
565 EmpathyAccountPriv *priv = GET_PRIV (account);
567 return priv->unique_name;
571 * empathy_account_get_display_name:
572 * @account: a #EmpathyAccount
574 * Returns: the display name of the account.
577 empathy_account_get_display_name (EmpathyAccount *account)
579 EmpathyAccountPriv *priv = GET_PRIV (account);
581 return priv->display_name;
585 empathy_account_is_valid (EmpathyAccount *account)
587 //EmpathyAccountPriv *priv = GET_PRIV (account);
594 empathy_account_get_connection_manager (EmpathyAccount *account)
596 EmpathyAccountPriv *priv = GET_PRIV (account);
598 return priv->cm_name;
602 empathy_account_get_protocol (EmpathyAccount *account)
604 EmpathyAccountPriv *priv = GET_PRIV (account);
606 return priv->proto_name;
610 empathy_account_get_icon_name (EmpathyAccount *account)
612 EmpathyAccountPriv *priv = GET_PRIV (account);
614 return priv->icon_name;
618 empathy_account_is_enabled (EmpathyAccount *account)
620 EmpathyAccountPriv *priv = GET_PRIV (account);
622 return priv->enabled;
626 empathy_account_unset_param (EmpathyAccount *account, const gchar *param)
628 //EmpathyAccountPriv *priv = GET_PRIV (account);
630 //mc_account_unset_param (priv->mc_account, param);
634 empathy_account_get_param_string (EmpathyAccount *account, const gchar *param)
636 EmpathyAccountPriv *priv = GET_PRIV (account);
638 return tp_asv_get_string (priv->parameters, param);
642 empathy_account_get_param_int (EmpathyAccount *account, const gchar *param)
644 EmpathyAccountPriv *priv = GET_PRIV (account);
646 return tp_asv_get_int32 (priv->parameters, param, NULL);
650 empathy_account_get_param_boolean (EmpathyAccount *account, const gchar *param)
652 EmpathyAccountPriv *priv = GET_PRIV (account);
654 return tp_asv_get_boolean (priv->parameters, param, NULL);
658 empathy_account_set_param_string (EmpathyAccount *account,
662 //EmpathyAccountPriv *priv = GET_PRIV (account);
663 //mc_account_set_param_string (priv->mc_account, param, value);
667 empathy_account_set_param_int (EmpathyAccount *account,
671 //EmpathyAccountPriv *priv = GET_PRIV (account);
672 //mc_account_set_param_int (priv->mc_account, param, value);
676 empathy_account_set_param_boolean (EmpathyAccount *account,
680 //EmpathyAccountPriv *priv = GET_PRIV (account);
681 //mc_account_set_param_boolean (priv->mc_account, param, value);
685 empathy_account_set_display_name (EmpathyAccount *account,
686 const gchar *display_name)
688 //EmpathyAccountPriv *priv = GET_PRIV (account);
689 //mc_account_set_display_name (priv->mc_account, display_name);
694 empathy_account_new (TpDBusDaemon *dbus, const gchar *unique_name)
696 return EMPATHY_ACCOUNT (g_object_new (EMPATHY_TYPE_ACCOUNT,
698 "unique-name", unique_name,
704 _empathy_account_new (McAccount *mc_account)
706 EmpathyAccount *account;
707 EmpathyAccountPriv *priv;
709 McProtocol *protocol;
712 account = g_object_new (EMPATHY_TYPE_ACCOUNT, NULL);
713 priv = GET_PRIV (account);
714 priv->mc_account = mc_account;
716 profile = mc_account_get_profile (mc_account);
717 protocol = mc_profile_get_protocol (profile);
719 if (protocol != NULL)
721 McManager *manager = mc_protocol_get_manager (protocol);
723 priv->proto_name = g_strdup (mc_protocol_get_name (protocol));
724 priv->cm_name = g_strdup (mc_manager_get_unique_name (manager));
726 g_object_unref (protocol);
727 g_object_unref (manager);
729 g_object_unref (profile);
735 _empathy_account_set_status (EmpathyAccount *account,
736 TpConnectionStatus status,
737 TpConnectionStatusReason reason,
738 TpConnectionPresenceType presence)
740 EmpathyAccountPriv *priv = GET_PRIV (account);
741 TpConnectionStatus old_s = priv->status;
742 TpConnectionPresenceType old_p = priv->presence;
744 priv->status = status;
745 priv->presence = presence;
751 empathy_account_connection_ready_cb (TpConnection *connection,
755 EmpathyAccount *account = EMPATHY_ACCOUNT (user_data);
756 EmpathyAccountPriv *priv = GET_PRIV (account);
760 DEBUG ("(%s) Connection failed to become ready: %s",
761 empathy_account_get_unique_name (account), error->message);
762 priv->connection = NULL;
766 DEBUG ("(%s) Connection ready",
767 empathy_account_get_unique_name (account));
768 g_object_notify (G_OBJECT (account), "connection");
773 _empathy_account_connection_invalidated_cb (TpProxy *self,
779 EmpathyAccount *account = EMPATHY_ACCOUNT (user_data);
780 EmpathyAccountPriv *priv = GET_PRIV (account);
782 if (priv->connection == NULL)
785 DEBUG ("(%s) Connection invalidated",
786 empathy_account_get_unique_name (account));
788 g_assert (priv->connection == TP_CONNECTION (self));
790 g_signal_handler_disconnect (priv->connection,
791 priv->connection_invalidated_id);
792 priv->connection_invalidated_id = 0;
794 g_object_unref (priv->connection);
795 priv->connection = NULL;
797 g_object_notify (G_OBJECT (account), "connection");
801 _empathy_account_set_connection (EmpathyAccount *account,
802 TpConnection *connection)
804 EmpathyAccountPriv *priv = GET_PRIV (account);
806 if (priv->connection == connection)
809 /* Connection already set, don't set the new one */
810 if (connection != NULL && priv->connection != NULL)
813 if (connection == NULL)
815 g_signal_handler_disconnect (priv->connection,
816 priv->connection_invalidated_id);
817 priv->connection_invalidated_id = 0;
819 g_object_unref (priv->connection);
820 priv->connection = NULL;
821 g_object_notify (G_OBJECT (account), "connection");
825 priv->connection = g_object_ref (connection);
826 priv->connection_invalidated_id = g_signal_connect (priv->connection,
828 G_CALLBACK (_empathy_account_connection_invalidated_cb),
831 DEBUG ("Readying connection for %s", priv->unique_name);
832 /* notify a change in the connection property when it's ready */
833 tp_connection_call_when_ready (priv->connection,
834 empathy_account_connection_ready_cb, account);
839 empathy_account_set_enabled (EmpathyAccount *account,
842 EmpathyAccountPriv *priv = GET_PRIV (account);
844 if (priv->enabled == enabled)
847 priv->enabled = enabled;
848 g_object_notify (G_OBJECT (account), "enabled");
853 _empathy_account_get_mc_account (EmpathyAccount *account)
855 EmpathyAccountPriv *priv = GET_PRIV (account);
857 return priv->mc_account;