1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007-2008 Collabora Ltd.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 * Authors: Xavier Claessens <xclaesse@gmail.com>
26 #include <telepathy-glib/account-manager.h>
27 #include <telepathy-glib/enums.h>
29 #include "empathy-contact-manager.h"
30 #include "empathy-contact-monitor.h"
31 #include "empathy-contact-list.h"
32 #include "empathy-utils.h"
34 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
35 #include "empathy-debug.h"
37 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactManager)
40 TpAccountManager *account_manager;
41 EmpathyContactMonitor *contact_monitor;
42 } EmpathyContactManagerPriv;
44 static void contact_manager_iface_init (EmpathyContactListIface *iface);
46 G_DEFINE_TYPE_WITH_CODE (EmpathyContactManager, empathy_contact_manager, G_TYPE_OBJECT,
47 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
48 contact_manager_iface_init));
50 static EmpathyContactManager *manager_singleton = NULL;
53 contact_manager_members_changed_cb (EmpathyTpContactList *list,
54 EmpathyContact *contact,
55 EmpathyContact *actor,
59 EmpathyContactManager *manager)
61 g_signal_emit_by_name (manager, "members-changed",
62 contact, actor, reason, message, is_member);
66 contact_manager_pendings_changed_cb (EmpathyTpContactList *list,
67 EmpathyContact *contact,
68 EmpathyContact *actor,
72 EmpathyContactManager *manager)
74 g_signal_emit_by_name (manager, "pendings-changed",
75 contact, actor, reason, message, is_pending);
79 contact_manager_groups_changed_cb (EmpathyTpContactList *list,
80 EmpathyContact *contact,
83 EmpathyContactManager *manager)
85 g_signal_emit_by_name (manager, "groups-changed",
86 contact, group, is_member);
90 contact_manager_invalidated_cb (TpProxy *connection,
94 EmpathyContactManager *manager)
96 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
97 EmpathyTpContactList *list;
99 DEBUG ("Removing connection: %s (%s)",
100 tp_proxy_get_object_path (TP_PROXY (connection)),
103 list = g_hash_table_lookup (priv->lists, connection);
105 empathy_tp_contact_list_remove_all (list);
106 g_hash_table_remove (priv->lists, connection);
111 contact_manager_disconnect_foreach (gpointer key,
115 TpConnection *connection = key;
116 EmpathyTpContactList *list = value;
117 EmpathyContactManager *manager = user_data;
119 /* Disconnect signals from the list */
120 g_signal_handlers_disconnect_by_func (list,
121 contact_manager_members_changed_cb,
123 g_signal_handlers_disconnect_by_func (list,
124 contact_manager_pendings_changed_cb,
126 g_signal_handlers_disconnect_by_func (list,
127 contact_manager_groups_changed_cb,
129 g_signal_handlers_disconnect_by_func (connection,
130 contact_manager_invalidated_cb,
135 contact_manager_status_changed_cb (TpAccount *account,
139 gchar *dbus_error_name,
141 EmpathyContactManager *self)
143 EmpathyContactManagerPriv *priv = GET_PRIV (self);
144 EmpathyTpContactList *list;
145 TpConnection *connection;
147 if (new_status == TP_CONNECTION_STATUS_DISCONNECTED)
148 /* No point to start tracking a connection which is about to die */
151 connection = tp_account_get_connection (account);
153 if (connection == NULL || g_hash_table_lookup (priv->lists, connection)) {
157 DEBUG ("Adding new connection: %s",
158 tp_proxy_get_object_path (TP_PROXY (connection)));
160 list = empathy_tp_contact_list_new (connection);
161 g_hash_table_insert (priv->lists, g_object_ref (connection), list);
162 g_signal_connect (connection, "invalidated",
163 G_CALLBACK (contact_manager_invalidated_cb),
166 /* Connect signals */
167 g_signal_connect (list, "members-changed",
168 G_CALLBACK (contact_manager_members_changed_cb),
170 g_signal_connect (list, "pendings-changed",
171 G_CALLBACK (contact_manager_pendings_changed_cb),
173 g_signal_connect (list, "groups-changed",
174 G_CALLBACK (contact_manager_groups_changed_cb),
179 contact_manager_finalize (GObject *object)
181 EmpathyContactManagerPriv *priv = GET_PRIV (object);
183 g_hash_table_foreach (priv->lists,
184 contact_manager_disconnect_foreach,
186 g_hash_table_destroy (priv->lists);
188 g_object_unref (priv->account_manager);
190 if (priv->contact_monitor) {
191 g_object_unref (priv->contact_monitor);
196 contact_manager_constructor (GType type,
198 GObjectConstructParam *props)
202 if (manager_singleton) {
203 retval = g_object_ref (manager_singleton);
205 retval = G_OBJECT_CLASS (empathy_contact_manager_parent_class)->constructor
206 (type, n_props, props);
208 manager_singleton = EMPATHY_CONTACT_MANAGER (retval);
209 g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
216 * empathy_contact_manager_initialized:
218 * Reports whether or not the singleton has already been created.
220 * There can be instances where you want to access the #EmpathyContactManager
221 * only if it has been set up for this process.
223 * Returns: %TRUE if the #EmpathyContactManager singleton has previously
227 empathy_contact_manager_initialized (void)
229 return (manager_singleton != NULL);
233 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
235 GObjectClass *object_class = G_OBJECT_CLASS (klass);
237 object_class->finalize = contact_manager_finalize;
238 object_class->constructor = contact_manager_constructor;
240 g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
244 account_manager_prepared_cb (GObject *source_object,
245 GAsyncResult *result,
249 EmpathyContactManager *manager = user_data;
250 TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
251 GError *error = NULL;
253 if (!tp_account_manager_prepare_finish (account_manager, result, &error)) {
254 DEBUG ("Failed to prepare account manager: %s", error->message);
255 g_error_free (error);
259 accounts = tp_account_manager_get_valid_accounts (account_manager);
261 for (l = accounts; l != NULL; l = l->next) {
262 TpAccount *account = l->data;
263 TpConnection *conn = tp_account_get_connection (account);
266 contact_manager_status_changed_cb (account, 0, 0, 0,
267 NULL, NULL, manager);
270 empathy_signal_connect_weak (account, "status-changed",
271 G_CALLBACK (contact_manager_status_changed_cb),
274 g_list_free (accounts);
278 empathy_contact_manager_init (EmpathyContactManager *manager)
280 EmpathyContactManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
281 EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv);
283 manager->priv = priv;
284 priv->lists = g_hash_table_new_full (empathy_proxy_hash,
286 (GDestroyNotify) g_object_unref,
287 (GDestroyNotify) g_object_unref);
288 priv->account_manager = tp_account_manager_dup ();
289 priv->contact_monitor = NULL;
291 tp_account_manager_prepare_async (priv->account_manager, NULL,
292 account_manager_prepared_cb, manager);
295 EmpathyContactManager *
296 empathy_contact_manager_dup_singleton (void)
298 return g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
301 EmpathyTpContactList *
302 empathy_contact_manager_get_list (EmpathyContactManager *manager,
303 TpConnection *connection)
305 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
307 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
308 g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
310 return g_hash_table_lookup (priv->lists, connection);
314 contact_manager_add (EmpathyContactList *manager,
315 EmpathyContact *contact,
316 const gchar *message)
318 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
319 EmpathyContactList *list;
320 TpConnection *connection;
322 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
324 connection = empathy_contact_get_connection (contact);
325 list = g_hash_table_lookup (priv->lists, connection);
328 empathy_contact_list_add (list, contact, message);
333 contact_manager_remove (EmpathyContactList *manager,
334 EmpathyContact *contact,
335 const gchar *message)
337 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
338 EmpathyContactList *list;
339 TpConnection *connection;
341 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
343 connection = empathy_contact_get_connection (contact);
344 list = g_hash_table_lookup (priv->lists, connection);
347 empathy_contact_list_remove (list, contact, message);
352 contact_manager_get_members_foreach (TpConnection *connection,
353 EmpathyTpContactList *list,
358 l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list));
359 *contacts = g_list_concat (*contacts, l);
363 contact_manager_get_members (EmpathyContactList *manager)
365 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
366 GList *contacts = NULL;
368 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
370 g_hash_table_foreach (priv->lists,
371 (GHFunc) contact_manager_get_members_foreach,
377 static EmpathyContactMonitor *
378 contact_manager_get_monitor (EmpathyContactList *manager)
380 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
382 if (priv->contact_monitor == NULL) {
383 priv->contact_monitor = empathy_contact_monitor_new_for_iface (manager);
386 return priv->contact_monitor;
390 contact_manager_get_pendings_foreach (TpConnection *connection,
391 EmpathyTpContactList *list,
396 l = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (list));
397 *contacts = g_list_concat (*contacts, l);
401 contact_manager_get_pendings (EmpathyContactList *manager)
403 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
404 GList *contacts = NULL;
406 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
408 g_hash_table_foreach (priv->lists,
409 (GHFunc) contact_manager_get_pendings_foreach,
416 contact_manager_get_all_groups_foreach (TpConnection *connection,
417 EmpathyTpContactList *list,
422 groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (list));
423 for (l = groups; l; l = l->next) {
424 if (!g_list_find_custom (*all_groups,
426 (GCompareFunc) strcmp)) {
427 *all_groups = g_list_prepend (*all_groups, l->data);
433 g_list_free (groups);
437 contact_manager_get_all_groups (EmpathyContactList *manager)
439 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
440 GList *groups = NULL;
442 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
444 g_hash_table_foreach (priv->lists,
445 (GHFunc) contact_manager_get_all_groups_foreach,
452 contact_manager_get_groups (EmpathyContactList *manager,
453 EmpathyContact *contact)
455 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
456 EmpathyContactList *list;
457 TpConnection *connection;
459 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
461 connection = empathy_contact_get_connection (contact);
462 list = g_hash_table_lookup (priv->lists, connection);
465 return empathy_contact_list_get_groups (list, contact);
472 contact_manager_add_to_group (EmpathyContactList *manager,
473 EmpathyContact *contact,
476 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
477 EmpathyContactList *list;
478 TpConnection *connection;
480 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
482 connection = empathy_contact_get_connection (contact);
483 list = g_hash_table_lookup (priv->lists, connection);
486 empathy_contact_list_add_to_group (list, contact, group);
491 contact_manager_remove_from_group (EmpathyContactList *manager,
492 EmpathyContact *contact,
495 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
496 EmpathyContactList *list;
497 TpConnection *connection;
499 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
501 connection = empathy_contact_get_connection (contact);
502 list = g_hash_table_lookup (priv->lists, connection);
505 empathy_contact_list_remove_from_group (list, contact, group);
510 const gchar *old_group;
511 const gchar *new_group;
515 contact_manager_rename_group_foreach (TpConnection *connection,
516 EmpathyTpContactList *list,
517 RenameGroupData *data)
519 empathy_contact_list_rename_group (EMPATHY_CONTACT_LIST (list),
525 contact_manager_rename_group (EmpathyContactList *manager,
526 const gchar *old_group,
527 const gchar *new_group)
529 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
530 RenameGroupData data;
532 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
534 data.old_group = old_group;
535 data.new_group = new_group;
536 g_hash_table_foreach (priv->lists,
537 (GHFunc) contact_manager_rename_group_foreach,
541 static void contact_manager_remove_group_foreach (TpConnection *connection,
542 EmpathyTpContactList *list,
545 empathy_contact_list_remove_group (EMPATHY_CONTACT_LIST (list),
550 contact_manager_remove_group (EmpathyContactList *manager,
553 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
555 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
557 g_hash_table_foreach (priv->lists,
558 (GHFunc) contact_manager_remove_group_foreach,
563 contact_manager_iface_init (EmpathyContactListIface *iface)
565 iface->add = contact_manager_add;
566 iface->remove = contact_manager_remove;
567 iface->get_members = contact_manager_get_members;
568 iface->get_monitor = contact_manager_get_monitor;
569 iface->get_pendings = contact_manager_get_pendings;
570 iface->get_all_groups = contact_manager_get_all_groups;
571 iface->get_groups = contact_manager_get_groups;
572 iface->add_to_group = contact_manager_add_to_group;
573 iface->remove_from_group = contact_manager_remove_from_group;
574 iface->rename_group = contact_manager_rename_group;
575 iface->remove_group = contact_manager_remove_group;
578 EmpathyContactListFlags
579 empathy_contact_manager_get_flags_for_connection (
580 EmpathyContactManager *manager,
581 TpConnection *connection)
583 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
584 EmpathyContactList *list;
585 EmpathyContactListFlags flags;
587 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), FALSE);
588 g_return_val_if_fail (connection != NULL, FALSE);
590 list = g_hash_table_lookup (priv->lists, connection);
594 flags = empathy_contact_list_get_flags (list);