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>
28 #include <telepathy-glib/proxy-subclass.h>
29 #include <telepathy-glib/util.h>
31 #include "empathy-contact-manager.h"
32 #include "empathy-contact-list.h"
33 #include "empathy-utils.h"
35 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
36 #include "empathy-debug.h"
38 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactManager)
40 /* Owned (TpConnection *) => Owned (TpContactList *)
41 The contact list associated with each connected connection */
43 TpAccountManager *account_manager;
44 } EmpathyContactManagerPriv;
46 static void contact_manager_iface_init (EmpathyContactListIface *iface);
48 G_DEFINE_TYPE_WITH_CODE (EmpathyContactManager, empathy_contact_manager, G_TYPE_OBJECT,
49 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
50 contact_manager_iface_init));
52 static EmpathyContactManager *manager_singleton = NULL;
55 contact_manager_members_changed_cb (EmpathyTpContactList *list,
56 EmpathyContact *contact,
57 EmpathyContact *actor,
61 EmpathyContactManager *manager)
63 g_signal_emit_by_name (manager, "members-changed",
64 contact, actor, reason, message, is_member);
68 contact_manager_pendings_changed_cb (EmpathyTpContactList *list,
69 EmpathyContact *contact,
70 EmpathyContact *actor,
74 EmpathyContactManager *manager)
76 g_signal_emit_by_name (manager, "pendings-changed",
77 contact, actor, reason, message, is_pending);
81 contact_manager_groups_changed_cb (EmpathyTpContactList *list,
82 EmpathyContact *contact,
85 EmpathyContactManager *manager)
87 g_signal_emit_by_name (manager, "groups-changed",
88 contact, group, is_member);
92 contact_manager_invalidated_cb (TpProxy *connection,
96 EmpathyContactManager *manager)
98 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
99 EmpathyTpContactList *list;
101 DEBUG ("Removing connection: %s (%s)",
102 tp_proxy_get_object_path (TP_PROXY (connection)),
105 list = g_hash_table_lookup (priv->lists, connection);
107 empathy_tp_contact_list_remove_all (list);
108 g_hash_table_remove (priv->lists, connection);
113 contact_manager_disconnect_foreach (gpointer key,
117 TpConnection *connection = key;
118 EmpathyTpContactList *list = value;
119 EmpathyContactManager *manager = user_data;
121 /* Disconnect signals from the list */
122 g_signal_handlers_disconnect_by_func (list,
123 contact_manager_members_changed_cb,
125 g_signal_handlers_disconnect_by_func (list,
126 contact_manager_pendings_changed_cb,
128 g_signal_handlers_disconnect_by_func (list,
129 contact_manager_groups_changed_cb,
131 g_signal_handlers_disconnect_by_func (connection,
132 contact_manager_invalidated_cb,
137 contact_manager_status_changed_cb (TpAccount *account,
141 gchar *dbus_error_name,
143 EmpathyContactManager *self)
145 EmpathyContactManagerPriv *priv = GET_PRIV (self);
146 EmpathyTpContactList *list;
147 TpConnection *connection;
149 if (new_status == TP_CONNECTION_STATUS_DISCONNECTED)
150 /* No point to start tracking a connection which is about to die */
153 connection = tp_account_get_connection (account);
155 if (connection == NULL || g_hash_table_lookup (priv->lists, connection)) {
159 DEBUG ("Adding new connection: %s",
160 tp_proxy_get_object_path (TP_PROXY (connection)));
162 list = empathy_tp_contact_list_new (connection);
163 g_hash_table_insert (priv->lists, g_object_ref (connection), list);
164 g_signal_connect (connection, "invalidated",
165 G_CALLBACK (contact_manager_invalidated_cb),
168 /* Connect signals */
169 g_signal_connect (list, "members-changed",
170 G_CALLBACK (contact_manager_members_changed_cb),
172 g_signal_connect (list, "pendings-changed",
173 G_CALLBACK (contact_manager_pendings_changed_cb),
175 g_signal_connect (list, "groups-changed",
176 G_CALLBACK (contact_manager_groups_changed_cb),
181 contact_manager_validity_changed_cb (TpAccountManager *account_manager,
184 EmpathyContactManager *manager)
187 tp_g_signal_connect_object (account, "status-changed",
188 G_CALLBACK (contact_manager_status_changed_cb),
194 contact_manager_finalize (GObject *object)
196 EmpathyContactManagerPriv *priv = GET_PRIV (object);
198 g_hash_table_foreach (priv->lists,
199 contact_manager_disconnect_foreach,
201 g_hash_table_unref (priv->lists);
203 g_object_unref (priv->account_manager);
207 contact_manager_constructor (GType type,
209 GObjectConstructParam *props)
213 if (manager_singleton) {
214 retval = g_object_ref (manager_singleton);
216 retval = G_OBJECT_CLASS (empathy_contact_manager_parent_class)->constructor
217 (type, n_props, props);
219 manager_singleton = EMPATHY_CONTACT_MANAGER (retval);
220 g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
227 * empathy_contact_manager_initialized:
229 * Reports whether or not the singleton has already been created.
231 * There can be instances where you want to access the #EmpathyContactManager
232 * only if it has been set up for this process.
234 * Returns: %TRUE if the #EmpathyContactManager singleton has previously
238 empathy_contact_manager_initialized (void)
240 return (manager_singleton != NULL);
244 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
246 GObjectClass *object_class = G_OBJECT_CLASS (klass);
248 object_class->finalize = contact_manager_finalize;
249 object_class->constructor = contact_manager_constructor;
251 g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
255 account_manager_prepared_cb (GObject *source_object,
256 GAsyncResult *result,
260 EmpathyContactManager *manager = user_data;
261 TpAccountManager *account_manager = TP_ACCOUNT_MANAGER (source_object);
262 GError *error = NULL;
264 if (!tp_proxy_prepare_finish (account_manager, result, &error)) {
265 DEBUG ("Failed to prepare account manager: %s", error->message);
266 g_error_free (error);
270 accounts = tp_account_manager_get_valid_accounts (account_manager);
272 for (l = accounts; l != NULL; l = l->next) {
273 TpAccount *account = l->data;
274 TpConnection *conn = tp_account_get_connection (account);
277 contact_manager_status_changed_cb (account, 0, 0, 0,
278 NULL, NULL, manager);
281 tp_g_signal_connect_object (account, "status-changed",
282 G_CALLBACK (contact_manager_status_changed_cb),
285 g_list_free (accounts);
287 tp_g_signal_connect_object (account_manager, "account-validity-changed",
288 G_CALLBACK (contact_manager_validity_changed_cb),
293 empathy_contact_manager_init (EmpathyContactManager *manager)
295 EmpathyContactManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
296 EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv);
298 manager->priv = priv;
299 priv->lists = g_hash_table_new_full (empathy_proxy_hash,
301 (GDestroyNotify) g_object_unref,
302 (GDestroyNotify) g_object_unref);
304 priv->account_manager = tp_account_manager_dup ();
306 tp_proxy_prepare_async (priv->account_manager, NULL,
307 account_manager_prepared_cb, manager);
310 EmpathyContactManager *
311 empathy_contact_manager_dup_singleton (void)
313 return g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
316 EmpathyTpContactList *
317 empathy_contact_manager_get_list (EmpathyContactManager *manager,
318 TpConnection *connection)
320 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
322 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
323 g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
325 return g_hash_table_lookup (priv->lists, connection);
329 contact_manager_add (EmpathyContactList *manager,
330 EmpathyContact *contact,
331 const gchar *message)
333 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
334 EmpathyContactList *list;
335 TpConnection *connection;
337 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
339 connection = empathy_contact_get_connection (contact);
340 list = g_hash_table_lookup (priv->lists, connection);
343 empathy_contact_list_add (list, contact, message);
348 contact_manager_remove (EmpathyContactList *manager,
349 EmpathyContact *contact,
350 const gchar *message)
352 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
353 EmpathyContactList *list;
354 TpConnection *connection;
356 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
358 connection = empathy_contact_get_connection (contact);
359 list = g_hash_table_lookup (priv->lists, connection);
362 empathy_contact_list_remove (list, contact, message);
367 contact_manager_get_members_foreach (TpConnection *connection,
368 EmpathyTpContactList *list,
373 l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list));
374 *contacts = g_list_concat (*contacts, l);
378 contact_manager_get_members (EmpathyContactList *manager)
380 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
381 GList *contacts = NULL;
383 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
385 g_hash_table_foreach (priv->lists,
386 (GHFunc) contact_manager_get_members_foreach,
393 contact_manager_get_pendings_foreach (TpConnection *connection,
394 EmpathyTpContactList *list,
399 l = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (list));
400 *contacts = g_list_concat (*contacts, l);
404 contact_manager_get_pendings (EmpathyContactList *manager)
406 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
407 GList *contacts = NULL;
409 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
411 g_hash_table_foreach (priv->lists,
412 (GHFunc) contact_manager_get_pendings_foreach,
419 contact_manager_get_all_groups_foreach (TpConnection *connection,
420 EmpathyTpContactList *list,
425 groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (list));
426 for (l = groups; l; l = l->next) {
427 if (!g_list_find_custom (*all_groups,
429 (GCompareFunc) strcmp)) {
430 *all_groups = g_list_prepend (*all_groups, l->data);
436 g_list_free (groups);
440 contact_manager_get_all_groups (EmpathyContactList *manager)
442 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
443 GList *groups = NULL;
445 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
447 g_hash_table_foreach (priv->lists,
448 (GHFunc) contact_manager_get_all_groups_foreach,
455 contact_manager_get_groups (EmpathyContactList *manager,
456 EmpathyContact *contact)
458 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
459 EmpathyContactList *list;
460 TpConnection *connection;
462 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
464 connection = empathy_contact_get_connection (contact);
465 list = g_hash_table_lookup (priv->lists, connection);
468 return empathy_contact_list_get_groups (list, contact);
475 contact_manager_add_to_group (EmpathyContactList *manager,
476 EmpathyContact *contact,
479 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
480 EmpathyContactList *list;
481 TpConnection *connection;
483 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
485 connection = empathy_contact_get_connection (contact);
486 list = g_hash_table_lookup (priv->lists, connection);
489 empathy_contact_list_add_to_group (list, contact, group);
494 contact_manager_remove_from_group (EmpathyContactList *manager,
495 EmpathyContact *contact,
498 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
499 EmpathyContactList *list;
500 TpConnection *connection;
502 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
504 connection = empathy_contact_get_connection (contact);
505 list = g_hash_table_lookup (priv->lists, connection);
508 empathy_contact_list_remove_from_group (list, contact, group);
513 const gchar *old_group;
514 const gchar *new_group;
518 contact_manager_rename_group_foreach (TpConnection *connection,
519 EmpathyTpContactList *list,
520 RenameGroupData *data)
522 empathy_contact_list_rename_group (EMPATHY_CONTACT_LIST (list),
528 contact_manager_rename_group (EmpathyContactList *manager,
529 const gchar *old_group,
530 const gchar *new_group)
532 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
533 RenameGroupData data;
535 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
537 data.old_group = old_group;
538 data.new_group = new_group;
539 g_hash_table_foreach (priv->lists,
540 (GHFunc) contact_manager_rename_group_foreach,
544 static void contact_manager_remove_group_foreach (TpConnection *connection,
545 EmpathyTpContactList *list,
548 empathy_contact_list_remove_group (EMPATHY_CONTACT_LIST (list),
553 contact_manager_remove_group (EmpathyContactList *manager,
556 EmpathyContactManagerPriv *priv = GET_PRIV (manager);
558 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
560 g_hash_table_foreach (priv->lists,
561 (GHFunc) contact_manager_remove_group_foreach,
566 contact_manager_iface_init (EmpathyContactListIface *iface)
568 iface->add = contact_manager_add;
569 iface->remove = contact_manager_remove;
570 iface->get_members = contact_manager_get_members;
571 iface->get_pendings = contact_manager_get_pendings;
572 iface->get_all_groups = contact_manager_get_all_groups;
573 iface->get_groups = contact_manager_get_groups;
574 iface->add_to_group = contact_manager_add_to_group;
575 iface->remove_from_group = contact_manager_remove_from_group;
576 iface->rename_group = contact_manager_rename_group;
577 iface->remove_group = contact_manager_remove_group;