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 <libmissioncontrol/mc-account-monitor.h>
26 #include "empathy-account-manager.h"
27 #include "empathy-account-priv.h"
28 #include "empathy-marshal.h"
29 #include "empathy-utils.h"
31 #define DEBUG_FLAG EMPATHY_DEBUG_ACCOUNT
32 #include <libempathy/empathy-debug.h>
34 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyAccountManager)
37 McAccountMonitor *monitor;
40 /* (owned) unique name -> (reffed) EmpathyAccount */
45 } EmpathyAccountManagerPriv;
53 ACCOUNT_CONNECTION_CHANGED,
54 ACCOUNT_PRESENCE_CHANGED,
59 static guint signals[LAST_SIGNAL];
60 static EmpathyAccountManager *manager_singleton = NULL;
62 G_DEFINE_TYPE (EmpathyAccountManager, empathy_account_manager, G_TYPE_OBJECT);
64 static TpConnectionPresenceType
65 mc_presence_to_tp_presence (McPresence presence)
69 case MC_PRESENCE_OFFLINE:
70 return TP_CONNECTION_PRESENCE_TYPE_OFFLINE;
71 case MC_PRESENCE_AVAILABLE:
72 return TP_CONNECTION_PRESENCE_TYPE_AVAILABLE;
73 case MC_PRESENCE_AWAY:
74 return TP_CONNECTION_PRESENCE_TYPE_AWAY;
75 case MC_PRESENCE_EXTENDED_AWAY:
76 return TP_CONNECTION_PRESENCE_TYPE_EXTENDED_AWAY;
77 case MC_PRESENCE_HIDDEN:
78 return TP_CONNECTION_PRESENCE_TYPE_HIDDEN;
79 case MC_PRESENCE_DO_NOT_DISTURB:
80 return TP_CONNECTION_PRESENCE_TYPE_BUSY;
82 return TP_CONNECTION_PRESENCE_TYPE_UNSET;
87 emp_account_connection_cb (EmpathyAccount *account,
91 TpConnection *connection = empathy_account_get_connection (account);
93 DEBUG ("Signalling connection %p of account %s",
94 connection, empathy_account_get_unique_name (account));
96 if (connection != NULL)
97 g_signal_emit (manager, signals[NEW_CONNECTION], 0, connection);
101 emp_account_status_changed_cb (EmpathyAccount *account,
102 TpConnectionStatus old,
103 TpConnectionStatus new,
104 TpConnectionStatusReason reason,
107 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
108 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
112 case TP_CONNECTION_STATUS_CONNECTING:
115 case TP_CONNECTION_STATUS_CONNECTED:
124 case TP_CONNECTION_STATUS_CONNECTING:
127 case TP_CONNECTION_STATUS_CONNECTED:
134 g_signal_emit (manager, signals[ACCOUNT_CONNECTION_CHANGED], 0,
135 account, reason, new, old);
139 emp_account_presence_changed_cb (EmpathyAccount *account,
140 TpConnectionPresenceType old,
141 TpConnectionPresenceType new,
144 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (user_data);
145 g_signal_emit (manager, signals[ACCOUNT_PRESENCE_CHANGED], 0,
149 static EmpathyAccount *
150 create_account (EmpathyAccountManager *manager,
151 const gchar *account_name,
152 McAccount *mc_account)
154 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
155 EmpathyAccount *account;
156 TpConnectionStatus status;
157 TpConnectionPresenceType presence;
158 McPresence mc_presence;
159 TpConnection *connection;
160 GError *error = NULL;
162 if ((account = g_hash_table_lookup (priv->accounts, account_name)) != NULL)
165 account = _empathy_account_new (mc_account);
166 g_hash_table_insert (priv->accounts, g_strdup (account_name),
169 _empathy_account_set_enabled (account,
170 mc_account_is_enabled (mc_account));
172 g_signal_emit (manager, signals[ACCOUNT_CREATED], 0, account);
174 g_signal_connect (account, "notify::connection",
175 G_CALLBACK (emp_account_connection_cb), manager);
177 connection = mission_control_get_tpconnection (priv->mc,
179 _empathy_account_set_connection (account, connection);
181 status = mission_control_get_connection_status (priv->mc,
186 status = TP_CONNECTION_STATUS_DISCONNECTED;
187 g_clear_error (&error);
190 mc_presence = mission_control_get_presence_actual (priv->mc, &error);
193 presence = TP_CONNECTION_PRESENCE_TYPE_UNSET;
194 g_clear_error (&error);
198 presence = mc_presence_to_tp_presence (mc_presence);
201 g_signal_connect (account, "status-changed",
202 G_CALLBACK (emp_account_status_changed_cb), manager);
204 g_signal_connect (account, "presence-changed",
205 G_CALLBACK (emp_account_presence_changed_cb), manager);
207 _empathy_account_set_status (account, status,
208 TP_CONNECTION_STATUS_REASON_NONE_SPECIFIED,
215 account_created_cb (McAccountMonitor *mon,
217 EmpathyAccountManager *manager)
219 McAccount *mc_account = mc_account_lookup (account_name);
221 if (mc_account != NULL)
222 create_account (manager, account_name, mc_account);
226 account_deleted_cb (McAccountMonitor *mon,
228 EmpathyAccountManager *manager)
230 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
231 EmpathyAccount *account;
233 account = g_hash_table_lookup (priv->accounts, account_name);
237 g_signal_emit (manager, signals[ACCOUNT_DELETED], 0, account);
238 g_hash_table_remove (priv->accounts, account_name);
243 account_changed_cb (McAccountMonitor *mon,
245 EmpathyAccountManager *manager)
247 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
248 EmpathyAccount *account;
250 account = g_hash_table_lookup (priv->accounts, account_name);
253 g_signal_emit (manager, signals[ACCOUNT_CHANGED], 0, account);
257 account_disabled_cb (McAccountMonitor *mon,
259 EmpathyAccountManager *manager)
261 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
262 EmpathyAccount *account;
264 account = g_hash_table_lookup (priv->accounts, account_name);
268 _empathy_account_set_enabled (account, FALSE);
269 g_signal_emit (manager, signals[ACCOUNT_DISABLED], 0, account);
274 account_enabled_cb (McAccountMonitor *mon,
276 EmpathyAccountManager *manager)
278 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
279 EmpathyAccount *account;
281 account = g_hash_table_lookup (priv->accounts, account_name);
285 _empathy_account_set_enabled (account, TRUE);
286 g_signal_emit (manager, signals[ACCOUNT_ENABLED], 0, account);
291 TpConnectionStatus status;
292 TpConnectionPresenceType presence;
293 TpConnectionStatusReason reason;
295 EmpathyAccountManager *manager;
296 McAccount *mc_account;
300 account_status_changed_idle_cb (ChangedSignalData *signal_data)
302 EmpathyAccount *account;
303 EmpathyAccountManager *manager = signal_data->manager;
304 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
306 account = g_hash_table_lookup (priv->accounts,
307 signal_data->unique_name);
311 if (empathy_account_get_connection (account) == NULL)
313 TpConnection *connection;
315 connection = mission_control_get_tpconnection (priv->mc,
316 signal_data->mc_account, NULL);
318 if (connection != NULL)
320 _empathy_account_set_connection (account, connection);
321 g_object_unref (connection);
325 _empathy_account_set_status (account, signal_data->status,
327 signal_data->presence);
330 g_object_unref (signal_data->manager);
331 g_object_unref (signal_data->mc_account);
332 g_free (signal_data->unique_name);
333 g_slice_free (ChangedSignalData, signal_data);
339 account_status_changed_cb (MissionControl *mc,
340 TpConnectionStatus status,
342 TpConnectionStatusReason reason,
343 const gchar *unique_name,
344 EmpathyAccountManager *manager)
346 ChangedSignalData *data;
348 DEBUG ("Status of account %s became "
349 "status: %d presence: %d reason: %d", unique_name, status,
352 data = g_slice_new0 (ChangedSignalData);
353 data->status = status;
354 data->presence = mc_presence_to_tp_presence (presence);
355 data->reason = reason;
356 data->unique_name = g_strdup (unique_name);
357 data->manager = g_object_ref (manager);
358 data->mc_account = mc_account_lookup (unique_name);
360 g_idle_add ((GSourceFunc) account_status_changed_idle_cb, data);
364 empathy_account_manager_init (EmpathyAccountManager *manager)
366 EmpathyAccountManagerPriv *priv;
367 GList *mc_accounts, *l;
369 priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
370 EMPATHY_TYPE_ACCOUNT_MANAGER, EmpathyAccountManagerPriv);
372 manager->priv = priv;
373 priv->monitor = mc_account_monitor_new ();
374 priv->mc = empathy_mission_control_dup_singleton ();
375 priv->connected = priv->connecting = 0;
376 priv->dispose_run = FALSE;
378 priv->accounts = g_hash_table_new_full (g_str_hash, g_str_equal,
379 g_free, (GDestroyNotify) g_object_unref);
381 mc_accounts = mc_accounts_list ();
383 for (l = mc_accounts; l; l = l->next)
384 account_created_cb (priv->monitor,
385 (char *) mc_account_get_unique_name (l->data), manager);
387 g_signal_connect (priv->monitor, "account-created",
388 G_CALLBACK (account_created_cb), manager);
389 g_signal_connect (priv->monitor, "account-deleted",
390 G_CALLBACK (account_deleted_cb), manager);
391 g_signal_connect (priv->monitor, "account-disabled",
392 G_CALLBACK (account_disabled_cb), manager);
393 g_signal_connect (priv->monitor, "account-enabled",
394 G_CALLBACK (account_enabled_cb), manager);
395 g_signal_connect (priv->monitor, "account-changed",
396 G_CALLBACK (account_changed_cb), manager);
398 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc), "AccountStatusChanged",
399 G_CALLBACK (account_status_changed_cb),
402 mc_accounts_list_free (mc_accounts);
406 do_finalize (GObject *obj)
408 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (obj);
409 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
411 g_hash_table_destroy (priv->accounts);
413 G_OBJECT_CLASS (empathy_account_manager_parent_class)->finalize (obj);
417 do_dispose (GObject *obj)
419 EmpathyAccountManager *manager = EMPATHY_ACCOUNT_MANAGER (obj);
420 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
422 if (priv->dispose_run)
425 priv->dispose_run = TRUE;
427 dbus_g_proxy_disconnect_signal (DBUS_G_PROXY (priv->mc),
428 "AccountStatusChanged",
429 G_CALLBACK (account_status_changed_cb),
434 g_signal_handlers_disconnect_by_func (priv->monitor,
435 account_created_cb, obj);
436 g_signal_handlers_disconnect_by_func (priv->monitor,
437 account_deleted_cb, obj);
438 g_signal_handlers_disconnect_by_func (priv->monitor,
439 account_disabled_cb, obj);
440 g_signal_handlers_disconnect_by_func (priv->monitor,
441 account_enabled_cb, obj);
442 g_signal_handlers_disconnect_by_func (priv->monitor,
443 account_changed_cb, obj);
444 g_object_unref (priv->monitor);
445 priv->monitor = NULL;
449 g_object_unref (priv->mc);
451 g_hash_table_remove_all (priv->accounts);
453 G_OBJECT_CLASS (empathy_account_manager_parent_class)->dispose (obj);
457 do_constructor (GType type,
458 guint n_construct_params,
459 GObjectConstructParam *construct_params)
463 if (!manager_singleton)
465 retval = G_OBJECT_CLASS (empathy_account_manager_parent_class)->constructor (type,
468 manager_singleton = EMPATHY_ACCOUNT_MANAGER (retval);
469 g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
473 retval = g_object_ref (manager_singleton);
480 empathy_account_manager_class_init (EmpathyAccountManagerClass *klass)
482 GObjectClass *oclass = G_OBJECT_CLASS (klass);
484 oclass->finalize = do_finalize;
485 oclass->dispose = do_dispose;
486 oclass->constructor = do_constructor;
488 signals[ACCOUNT_CREATED] =
489 g_signal_new ("account-created",
490 G_TYPE_FROM_CLASS (klass),
494 g_cclosure_marshal_VOID__OBJECT,
496 1, EMPATHY_TYPE_ACCOUNT);
498 signals[ACCOUNT_DELETED] =
499 g_signal_new ("account-deleted",
500 G_TYPE_FROM_CLASS (klass),
504 g_cclosure_marshal_VOID__OBJECT,
506 1, EMPATHY_TYPE_ACCOUNT);
508 signals[ACCOUNT_ENABLED] =
509 g_signal_new ("account-enabled",
510 G_TYPE_FROM_CLASS (klass),
514 g_cclosure_marshal_VOID__OBJECT,
516 1, EMPATHY_TYPE_ACCOUNT);
518 signals[ACCOUNT_DISABLED] =
519 g_signal_new ("account-disabled",
520 G_TYPE_FROM_CLASS (klass),
524 g_cclosure_marshal_VOID__OBJECT,
526 1, EMPATHY_TYPE_ACCOUNT);
528 signals[ACCOUNT_CHANGED] =
529 g_signal_new ("account-changed",
530 G_TYPE_FROM_CLASS (klass),
534 g_cclosure_marshal_VOID__OBJECT,
536 1, EMPATHY_TYPE_ACCOUNT);
538 signals[ACCOUNT_CONNECTION_CHANGED] =
539 g_signal_new ("account-connection-changed",
540 G_TYPE_FROM_CLASS (klass),
544 _empathy_marshal_VOID__OBJECT_INT_UINT_UINT,
546 4, EMPATHY_TYPE_ACCOUNT,
547 G_TYPE_INT, /* reason */
548 G_TYPE_UINT, /* actual connection */
549 G_TYPE_UINT); /* previous connection */
551 signals[ACCOUNT_PRESENCE_CHANGED] =
552 g_signal_new ("account-presence-changed",
553 G_TYPE_FROM_CLASS (klass),
557 _empathy_marshal_VOID__OBJECT_INT_INT,
559 3, EMPATHY_TYPE_ACCOUNT,
560 G_TYPE_INT, /* actual presence */
561 G_TYPE_INT); /* previous presence */
563 signals[NEW_CONNECTION] =
564 g_signal_new ("new-connection",
565 G_TYPE_FROM_CLASS (klass),
569 g_cclosure_marshal_VOID__OBJECT,
571 1, TP_TYPE_CONNECTION);
573 g_type_class_add_private (oclass, sizeof (EmpathyAccountManagerPriv));
578 EmpathyAccountManager *
579 empathy_account_manager_dup_singleton (void)
581 return g_object_new (EMPATHY_TYPE_ACCOUNT_MANAGER, NULL);
585 empathy_account_manager_create (EmpathyAccountManager *manager,
588 McAccount *mc_account = mc_account_create (profile);
589 return g_object_ref (create_account (manager,
590 mc_account_get_unique_name (mc_account),
595 empathy_account_manager_get_connected_accounts (EmpathyAccountManager *manager)
597 EmpathyAccountManagerPriv *priv;
599 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
601 priv = GET_PRIV (manager);
603 return priv->connected;
607 empathy_account_manager_get_connecting_accounts (EmpathyAccountManager *manager)
609 EmpathyAccountManagerPriv *priv;
611 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
613 priv = GET_PRIV (manager);
615 return priv->connecting;
619 * empathy_account_manager_get_count:
620 * @manager: a #EmpathyAccountManager
622 * Get the number of accounts.
624 * Returns: the number of accounts.
627 empathy_account_manager_get_count (EmpathyAccountManager *manager)
629 EmpathyAccountManagerPriv *priv;
631 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
633 priv = GET_PRIV (manager);
635 return g_hash_table_size (priv->accounts);
639 empathy_account_manager_get_account (EmpathyAccountManager *manager,
640 TpConnection *connection)
642 EmpathyAccountManagerPriv *priv;
646 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), 0);
648 priv = GET_PRIV (manager);
650 g_hash_table_iter_init (&iter, priv->accounts);
651 while (g_hash_table_iter_next (&iter, NULL, &value))
653 EmpathyAccount *account = EMPATHY_ACCOUNT (value);
655 if (connection == empathy_account_get_connection (account))
663 empathy_account_manager_lookup (EmpathyAccountManager *manager,
664 const gchar *unique_name)
666 EmpathyAccountManagerPriv *priv = GET_PRIV (manager);
667 EmpathyAccount *account;
669 account = g_hash_table_lookup (priv->accounts, unique_name);
672 g_object_ref (account);
678 empathy_account_manager_dup_accounts (EmpathyAccountManager *manager)
680 EmpathyAccountManagerPriv *priv;
683 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL);
685 priv = GET_PRIV (manager);
687 ret = g_hash_table_get_values (priv->accounts);
688 g_list_foreach (ret, (GFunc) g_object_ref, NULL);
694 * empathy_account_manager_dup_connections:
695 * @manager: a #EmpathyAccountManager
697 * Get a #GList of all ready #TpConnection. The list must be freed with
698 * g_list_free, and its elements must be unreffed.
700 * Returns: the list of connections
703 empathy_account_manager_dup_connections (EmpathyAccountManager *manager)
705 EmpathyAccountManagerPriv *priv;
710 g_return_val_if_fail (EMPATHY_IS_ACCOUNT_MANAGER (manager), NULL);
712 priv = GET_PRIV (manager);
714 g_hash_table_iter_init (&iter, priv->accounts);
715 while (g_hash_table_iter_next (&iter, NULL, &value))
717 EmpathyAccount *account = EMPATHY_ACCOUNT (value);
718 TpConnection *connection;
720 connection = empathy_account_get_connection (account);
721 if (connection != NULL)
722 ret = g_list_prepend (ret, g_object_ref (connection));
729 empathy_account_manager_remove (EmpathyAccountManager *manager,
730 EmpathyAccount *account)
732 mc_account_delete (_empathy_account_get_mc_account (account));