2 * Copyright (C) 2008 Collabora Ltd.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 * Authors: Cosimo Cecchi <cosimo.cecchi@collabora.co.uk>
19 * Sjoerd Simons <sjoerd.simons@collabora.co.uk>
24 #include <telepathy-glib/util.h>
25 #include <telepathy-glib/account-manager.h>
26 #include <telepathy-glib/enums.h>
27 #include <telepathy-glib/defs.h>
28 #include <telepathy-glib/interfaces.h>
30 #include "empathy-account-manager.h"
31 #include "empathy-marshal.h"
32 #include "empathy-utils.h"
34 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
35 #include <libempathy/empathy-debug.h>
37 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountManager)
39 #define MC5_BUS_NAME "org.freedesktop.Telepathy.MissionControl5"
42 /* (owned) unique name -> (reffed) EmpathyAccount */
47 TpProxySignalConnection *proxy_signal;
48 TpAccountManager *tp_manager;
52 EmpathyAccount *global_account;
54 TpConnectionPresenceType global_presence;
56 gchar *global_status_message;
57 } EmpathyAccountManagerPriv;
65 ACCOUNT_CONNECTION_CHANGED,
66 GLOBAL_PRESENCE_CHANGED,
71 static guint signals[LAST_SIGNAL];
72 static EmpathyAccountManager *manager_singleton = NULL;
74 G_DEFINE_TYPE (EmpathyAccountManager, empathy_account_manager, G_TYPE_OBJECT);
77 emp_account_connection_cb (EmpathyAccount *account,
81 TpConnection *connection = empathy_account_get_connection (account);
83 DEBUG ("Signalling connection %p of account %s",
84 connection, empathy_account_get_unique_name (account));
86 if (connection != NULL)
87 g_signal_emit (manager, signals[NEW_CONNECTION], 0, connection);
91 emp_account_enabled_cb (EmpathyAccount *account,
95 if (empathy_account_is_enabled (account))
96 g_signal_emit (manager, signals[ACCOUNT_ENABLED], 0, account);
98 g_signal_emit (manager, signals[ACCOUNT_DISABLED], 0, account);
102 emp_account_status_changed_cb (EmpathyAccount *account,
103 TpConnectionStatus old,
104 TpConnectionStatus new,
105 TpConnectionStatusReason reason,
108 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
109 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
113 case TP_CONNECTION_STATUS_CONNECTING:
116 case TP_CONNECTION_STATUS_CONNECTED:
125 case TP_CONNECTION_STATUS_CONNECTING:
128 case TP_CONNECTION_STATUS_CONNECTED:
135 g_signal_emit (manager, signals[ACCOUNT_CONNECTION_CHANGED], 0,
136 account, reason, new, old);
140 emp_account_manager_update_global_presence (EmpathyAccountManager *manager)
142 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
143 TpConnectionPresenceType presence = TP_CONNECTION_PRESENCE_TYPE_UNSET;
144 EmpathyAccount *account = NULL;
148 g_hash_table_iter_init (&iter, priv->accounts);
149 while (g_hash_table_iter_next (&iter, NULL, &value))
151 EmpathyAccount *a = EMPATHY_ACCOUNT (value);
152 TpConnectionPresenceType p;
154 g_object_get (a, "presence", &p, NULL);
156 if (tp_connection_presence_type_cmp_availability (p, presence) > 0)
163 priv->global_account = account;
164 g_free (priv->global_status);
165 g_free (priv->global_status_message);
169 priv->global_status = NULL;
170 priv->global_status_message = NULL;
174 g_object_get (account,
175 "presence", &priv->global_presence,
176 "status", &priv->global_status,
177 "status-message", &priv->global_status_message,
182 emp_account_presence_changed_cb (EmpathyAccount *account,
183 TpConnectionPresenceType presence,
185 const gchar *status_message,
188 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
189 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
191 if (tp_connection_presence_type_cmp_availability (presence,
192 priv->global_presence) > 0)
194 priv->global_account = account;
196 priv->global_presence = presence;
198 g_free (priv->global_status);
199 priv->global_status = g_strdup (status);
201 g_free (priv->global_status_message);
202 priv->global_status_message = g_strdup (status_message);
206 else if (priv->global_account == account)
208 emp_account_manager_update_global_presence (manager);
214 g_signal_emit (manager, signals[GLOBAL_PRESENCE_CHANGED], 0,
215 priv->global_presence, priv->global_status, priv->global_status_message);
219 emp_account_ready_cb (GObject *obj, GParamSpec *spec, gpointer user_data)
221 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
222 EmpathyAccount *account = EMPATHY_ACCOUNT (obj);
225 g_object_get (account, "ready", &ready, NULL);
230 g_signal_emit (manager, signals[ACCOUNT_CREATED], 0, account);
232 g_signal_connect (account, "notify::connection",
233 G_CALLBACK (emp_account_connection_cb), manager);
235 g_signal_connect (account, "notify::enabled",
236 G_CALLBACK (emp_account_enabled_cb), manager);
238 g_signal_connect (account, "status-changed",
239 G_CALLBACK (emp_account_status_changed_cb), manager);
241 g_signal_connect (account, "presence-changed",
242 G_CALLBACK (emp_account_presence_changed_cb), manager);
246 account_manager_got_all_cb (TpProxy *proxy,
247 GHashTable *properties,
250 GObject *weak_object)
252 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (weak_object);
253 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
259 DEBUG ("Failed to get account manager properties: %s", error->message);
263 accounts = tp_asv_get_boxed (properties, "ValidAccounts",
264 EMPATHY_ARRAY_TYPE_OBJECT);
267 for (i = 0; i < accounts->len; i++)
269 EmpathyAccount *account;
270 gchar *name = g_ptr_array_index (accounts, i);
272 account = empathy_account_new (priv->dbus, name);
273 g_hash_table_insert (priv->accounts, g_strdup (name), account);
275 g_signal_connect (account, "notify::ready",
276 G_CALLBACK (emp_account_ready_cb), manager);
281 account_manager_name_owner_changed_cb (TpDBusDaemon *proxy,
286 GObject *weak_object)
288 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (weak_object);
289 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
291 tp_proxy_signal_connection_disconnect (priv->proxy_signal);
292 priv->proxy_signal = NULL;
294 priv->tp_manager = tp_account_manager_new (priv->dbus);
295 tp_cli_dbus_properties_call_get_all (priv->tp_manager, -1,
296 TP_IFACE_ACCOUNT_MANAGER,
297 account_manager_got_all_cb,
304 empathy_account_manager_init (EmpathyAccountManager *manager)
306 EmpathyAccountManagerPriv *priv;
309 priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
310 EMPATHY_TYPE_ACCOUNT_MANAGER, EmpathyAccountManagerPriv);
312 manager->priv = priv;
313 priv->connected = priv->connecting = 0;
314 priv->global_presence = TP_CONNECTION_PRESENCE_TYPE_UNSET;
316 priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
317 g_free, (GDestroyNotify) g_object_unref);
319 priv->dbus = tp_dbus_daemon_dup (NULL);
321 priv->proxy_signal = tp_cli_dbus_daemon_connect_to_name_owner_changed (
323 account_manager_name_owner_changed_cb,
324 TP_ACCOUNT_MANAGER_BUS_NAME,
329 /* trigger MC5 starting */
330 mc5_proxy = g_object_new (TP_TYPE_PROXY,
331 "dbus-daemon", priv->dbus,
332 "dbus-connection", tp_proxy_get_dbus_connection (TP_PROXY (priv->dbus)),
333 "bus-name", MC5_BUS_NAME,
337 tp_cli_dbus_peer_call_ping (mc5_proxy, -1, NULL, NULL, NULL, NULL);
339 g_object_unref (mc5_proxy);
343 do_finalize (GObject *obj)
345 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (obj);
346 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
348 g_hash_table_destroy (priv->accounts);
350 G_OBJECT_CLASS (empathy_account_manager_parent_class)->finalize (obj);
354 do_dispose (GObject *obj)
356 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (obj);
357 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
359 if (priv->dispose_run)
362 priv->dispose_run = TRUE;
364 if (priv->dbus == NULL)
365 g_object_unref (priv->dbus);
368 G_OBJECT_CLASS (empathy_account_manager_parent_class)->dispose (obj);
372 do_constructor (GType type,
373 guint n_construct_params,
374 GObjectConstructParam *construct_params)
378 if (!manager_singleton)
380 retval = G_OBJECT_CLASS (empathy_account_manager_parent_class)->constructor (type,
383 manager_singleton = EMPATHY_ACCOUNT_MANAGER (retval);
384 g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
388 retval = g_object_ref (manager_singleton);
395 empathy_account_manager_class_init (EmpathyAccountManagerClass *klass)
397 GObjectClass *oclass = G_OBJECT_CLASS (klass);
399 oclass->finalize = do_finalize;
400 oclass->dispose = do_dispose;
401 oclass->constructor = do_constructor;
403 signals[ACCOUNT_CREATED] =
404 g_signal_new ("account-created",
405 G_TYPE_FROM_CLASS (klass),
409 g_cclosure_marshal_VOID__OBJECT,
411 1, EMPATHY_TYPE_ACCOUNT);
413 signals[ACCOUNT_DELETED] =
414 g_signal_new ("account-deleted",
415 G_TYPE_FROM_CLASS (klass),
419 g_cclosure_marshal_VOID__OBJECT,
421 1, EMPATHY_TYPE_ACCOUNT);
423 signals[ACCOUNT_ENABLED] =
424 g_signal_new ("account-enabled",
425 G_TYPE_FROM_CLASS (klass),
429 g_cclosure_marshal_VOID__OBJECT,
431 1, EMPATHY_TYPE_ACCOUNT);
433 signals[ACCOUNT_DISABLED] =
434 g_signal_new ("account-disabled",
435 G_TYPE_FROM_CLASS (klass),
439 g_cclosure_marshal_VOID__OBJECT,
441 1, EMPATHY_TYPE_ACCOUNT);
443 signals[ACCOUNT_CHANGED] =
444 g_signal_new ("account-changed",
445 G_TYPE_FROM_CLASS (klass),
449 g_cclosure_marshal_VOID__OBJECT,
451 1, EMPATHY_TYPE_ACCOUNT);
453 signals[ACCOUNT_CONNECTION_CHANGED] =
454 g_signal_new ("account-connection-changed",
455 G_TYPE_FROM_CLASS (klass),
459 _empathy_marshal_VOID__OBJECT_INT_UINT_UINT,
461 4, EMPATHY_TYPE_ACCOUNT,
462 G_TYPE_INT, /* reason */
463 G_TYPE_UINT, /* actual connection */
464 G_TYPE_UINT); /* previous connection */
466 signals[GLOBAL_PRESENCE_CHANGED] =
467 g_signal_new ("global-presence-changed",
468 G_TYPE_FROM_CLASS (klass),
472 _empathy_marshal_VOID__UINT_STRING_STRING,
474 3, G_TYPE_UINT, /* Presence type */
475 G_TYPE_STRING, /* status */
476 G_TYPE_STRING); /* stauts message*/
478 signals[NEW_CONNECTION] =
479 g_signal_new ("new-connection",
480 G_TYPE_FROM_CLASS (klass),
484 g_cclosure_marshal_VOID__OBJECT,
486 1, TP_TYPE_CONNECTION);
488 g_type_class_add_private (oclass, sizeof (EmpathyAccountManagerPriv));
493 EmpathyAccountManager *
494 empathy_account_manager_dup_singleton (void)
496 return g_object_new (EMPATHY_TYPE_ACCOUNT_MANAGER, NULL);
500 empathy_account_manager_create (EmpathyAccountManager *manager,
501 const gchar *connection_manager,
502 const gchar *protocol,
503 const gchar *display_name)
510 empathy_account_manager_get_connected_accounts (EmpathyAccountManager *manager)
512 EmpathyAccountManagerPriv *priv;
514 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
516 priv = GET_PRIV (manager);
518 return priv->connected;
522 empathy_account_manager_get_connecting_accounts (EmpathyAccountManager *manager)
524 EmpathyAccountManagerPriv *priv;
526 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
528 priv = GET_PRIV (manager);
530 return priv->connecting;
534 * empathy_account_manager_get_count:
535 * @manager: a #EmpathyAccountManager
537 * Get the number of accounts.
539 * Returns: the number of accounts.
542 empathy_account_manager_get_count (EmpathyAccountManager *manager)
544 EmpathyAccountManagerPriv *priv;
546 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
548 priv = GET_PRIV (manager);
550 return g_hash_table_size (priv->accounts);
554 empathy_account_manager_get_account (EmpathyAccountManager *manager,
555 TpConnection *connection)
557 EmpathyAccountManagerPriv *priv;
561 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
563 priv = GET_PRIV (manager);
565 g_hash_table_iter_init (&iter, priv->accounts);
566 while (g_hash_table_iter_next (&iter, NULL, &value))
568 EmpathyAccount *account = EMPATHY_ACCOUNT (value);
570 if (connection == empathy_account_get_connection (account))
578 empathy_account_manager_lookup (EmpathyAccountManager *manager,
579 const gchar *unique_name)
581 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
582 EmpathyAccount *account;
584 account = g_hash_table_lookup (priv->accounts, unique_name);
587 g_object_ref (account);
593 empathy_account_manager_dup_accounts (EmpathyAccountManager *manager)
595 EmpathyAccountManagerPriv *priv;
598 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL);
600 priv = GET_PRIV (manager);
602 ret = g_hash_table_get_values (priv->accounts);
603 g_list_foreach (ret, (GFunc) g_object_ref, NULL);
609 * empathy_account_manager_dup_connections:
610 * @manager: a #EmpathyAccountManager
612 * Get a #GList of all ready #TpConnection. The list must be freed with
613 * g_list_free, and its elements must be unreffed.
615 * Returns: the list of connections
618 empathy_account_manager_dup_connections (EmpathyAccountManager *manager)
620 EmpathyAccountManagerPriv *priv;
625 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL);
627 priv = GET_PRIV (manager);
629 g_hash_table_iter_init (&iter, priv->accounts);
630 while (g_hash_table_iter_next (&iter, NULL, &value))
632 EmpathyAccount *account = EMPATHY_ACCOUNT (value);
633 TpConnection *connection;
635 connection = empathy_account_get_connection (account);
636 if (connection != NULL)
637 ret = g_list_prepend (ret, g_object_ref (connection));
644 empathy_account_manager_remove (EmpathyAccountManager *manager,
645 EmpathyAccount *account)
652 empathy_account_manager_request_global_presence (
653 EmpathyAccountManager *manager,
654 TpConnectionPresenceType type,
656 const gchar *message)
658 /* FIXME should remember requested presence and set it on new accounts
660 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
664 g_hash_table_iter_init (&iter, priv->accounts);
665 while (g_hash_table_iter_next (&iter, NULL, &value))
667 EmpathyAccount *account = EMPATHY_ACCOUNT (value);
670 g_object_get (account, "ready", &ready, NULL);
673 empathy_account_request_presence (account, type, status, message);
677 TpConnectionPresenceType
678 empathy_account_manager_get_global_presence (
679 EmpathyAccountManager *manager,
683 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
686 *status = g_strdup (priv->global_status);
688 *message = g_strdup (priv->global_status_message);
690 return priv->global_presence;