1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2007 Collabora Ltd.
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This program 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 * General Public License for more details.
15 * You should have received a copy of the GNU General Public
16 * License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
27 #include <libtelepathy/tp-constants.h>
29 #include "empathy-contact-manager.h"
30 #include "empathy-contact-list.h"
31 #include "empathy-utils.h"
32 #include "empathy-debug.h"
34 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
35 EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv))
37 #define DEBUG_DOMAIN "ContactManager"
39 struct _EmpathyContactManagerPriv {
46 const gchar *old_group;
47 const gchar *new_group;
48 } ContactManagerRenameGroupData;
51 EmpathyContact *contact;
53 } ContactManagerFindData;
55 static void empathy_contact_manager_class_init (EmpathyContactManagerClass *klass);
56 static void contact_manager_iface_init (EmpathyContactListIface *iface);
57 static void empathy_contact_manager_init (EmpathyContactManager *manager);
58 static void contact_manager_finalize (GObject *object);
59 static void contact_manager_setup (EmpathyContactList *manager);
60 static EmpathyContact *contact_manager_find (EmpathyContactList *manager,
62 static void contact_manager_add (EmpathyContactList *manager,
63 EmpathyContact *contact,
64 const gchar *message);
65 static void contact_manager_remove (EmpathyContactList *manager,
66 EmpathyContact *contact,
67 const gchar *message);
68 static GList * contact_manager_get_members (EmpathyContactList *manager);
69 static GList * contact_manager_get_local_pending (EmpathyContactList *manager);
70 static void contact_manager_process_pending (EmpathyContactList *manager,
71 EmpathyContact *contact,
73 static void contact_manager_setup_foreach (McAccount *account,
74 EmpathyTpContactList *list,
75 EmpathyContactManager *manager);
76 static gboolean contact_manager_find_foreach (McAccount *account,
77 EmpathyTpContactList *list,
78 ContactManagerFindData *data);
79 static void contact_manager_add_account (EmpathyContactManager *manager,
81 static void contact_manager_added_cb (EmpathyTpContactList *list,
82 EmpathyContact *contact,
83 EmpathyContactManager *manager);
84 static void contact_manager_removed_cb (EmpathyTpContactList *list,
85 EmpathyContact *contact,
86 EmpathyContactManager *manager);
87 static void contact_manager_local_pending_cb (EmpathyTpContactList *list,
88 EmpathyContact *contact,
90 EmpathyContactManager *manager);
91 static void contact_manager_destroy_cb (EmpathyTpContactList *list,
92 EmpathyContactManager *manager);
93 static void contact_manager_rename_group_foreach (McAccount *account,
94 EmpathyTpContactList *list,
95 ContactManagerRenameGroupData *data);
96 static void contact_manager_get_groups_foreach (McAccount *account,
97 EmpathyTpContactList *list,
99 static void contact_manager_get_members_foreach (McAccount *account,
100 EmpathyTpContactList *list,
102 static void contact_manager_get_local_pending_foreach (McAccount *account,
103 EmpathyTpContactList *list,
105 static void contact_manager_status_changed_cb (MissionControl *mc,
106 TelepathyConnectionStatus status,
108 TelepathyConnectionStatusReason reason,
109 const gchar *unique_name,
110 EmpathyContactManager *manager);
112 G_DEFINE_TYPE_WITH_CODE (EmpathyContactManager, empathy_contact_manager, G_TYPE_OBJECT,
113 G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
114 contact_manager_iface_init));
117 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
119 GObjectClass *object_class = G_OBJECT_CLASS (klass);
121 object_class->finalize = contact_manager_finalize;
123 g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
127 contact_manager_iface_init (EmpathyContactListIface *iface)
129 iface->setup = contact_manager_setup;
130 iface->find = contact_manager_find;
131 iface->add = contact_manager_add;
132 iface->remove = contact_manager_remove;
133 iface->get_members = contact_manager_get_members;
134 iface->get_local_pending = contact_manager_get_local_pending;
135 iface->process_pending = contact_manager_process_pending;
139 empathy_contact_manager_init (EmpathyContactManager *manager)
141 EmpathyContactManagerPriv *priv;
142 GSList *accounts, *l;
144 priv = GET_PRIV (manager);
146 priv->lists = g_hash_table_new_full (empathy_account_hash,
147 empathy_account_equal,
148 (GDestroyNotify) g_object_unref,
149 (GDestroyNotify) g_object_unref);
151 priv->mc = empathy_mission_control_new ();
153 dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
154 "AccountStatusChanged",
155 G_CALLBACK (contact_manager_status_changed_cb),
158 /* Get ContactList for existing connections */
159 accounts = mission_control_get_online_connections (priv->mc, NULL);
160 for (l = accounts; l; l = l->next) {
164 contact_manager_add_account (manager, account);
166 g_object_unref (account);
168 g_slist_free (accounts);
172 contact_manager_finalize (GObject *object)
174 EmpathyContactManagerPriv *priv;
176 priv = GET_PRIV (object);
178 g_hash_table_destroy (priv->lists);
179 g_object_unref (priv->mc);
182 EmpathyContactManager *
183 empathy_contact_manager_new (void)
185 static EmpathyContactManager *manager = NULL;
188 manager = g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
189 g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
191 g_object_ref (manager);
198 contact_manager_setup (EmpathyContactList *manager)
200 EmpathyContactManagerPriv *priv;
202 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
204 priv = GET_PRIV (manager);
211 g_hash_table_foreach (priv->lists,
212 (GHFunc) contact_manager_setup_foreach,
218 static EmpathyContact *
219 contact_manager_find (EmpathyContactList *manager,
222 EmpathyContactManagerPriv *priv;
223 ContactManagerFindData data;
225 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
226 g_return_val_if_fail (id != NULL, NULL);
228 priv = GET_PRIV (manager);
233 g_hash_table_find (priv->lists,
234 (GHRFunc) contact_manager_find_foreach,
241 contact_manager_add (EmpathyContactList *manager,
242 EmpathyContact *contact,
243 const gchar *message)
245 EmpathyContactManagerPriv *priv;
246 EmpathyContactList *list;
249 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
250 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
252 priv = GET_PRIV (manager);
254 account = empathy_contact_get_account (contact);
255 list = g_hash_table_lookup (priv->lists, account);
258 empathy_contact_list_add (list, contact, message);
263 contact_manager_remove (EmpathyContactList *manager,
264 EmpathyContact *contact,
265 const gchar *message)
267 EmpathyContactManagerPriv *priv;
268 EmpathyContactList *list;
271 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
272 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
274 priv = GET_PRIV (manager);
276 account = empathy_contact_get_account (contact);
277 list = g_hash_table_lookup (priv->lists, account);
280 empathy_contact_list_remove (list, contact, message);
285 contact_manager_get_members (EmpathyContactList *manager)
287 EmpathyContactManagerPriv *priv;
288 GList *contacts = NULL;
290 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
292 priv = GET_PRIV (manager);
294 g_hash_table_foreach (priv->lists,
295 (GHFunc) contact_manager_get_members_foreach,
302 contact_manager_get_local_pending (EmpathyContactList *manager)
304 EmpathyContactManagerPriv *priv;
305 GList *pending = NULL;
307 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
309 priv = GET_PRIV (manager);
311 g_hash_table_foreach (priv->lists,
312 (GHFunc) contact_manager_get_local_pending_foreach,
319 contact_manager_process_pending (EmpathyContactList *manager,
320 EmpathyContact *contact,
323 EmpathyContactManagerPriv *priv;
324 EmpathyContactList *list;
327 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
328 g_return_if_fail (EMPATHY_IS_CONTACT (contact));
330 priv = GET_PRIV (manager);
332 account = empathy_contact_get_account (contact);
333 list = g_hash_table_lookup (priv->lists, account);
336 empathy_contact_list_process_pending (list, contact, accept);
340 EmpathyTpContactList *
341 empathy_contact_manager_get_list (EmpathyContactManager *manager,
344 EmpathyContactManagerPriv *priv;
346 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
347 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
349 priv = GET_PRIV (manager);
351 return g_hash_table_lookup (priv->lists, account);
355 empathy_contact_manager_get_user (EmpathyContactManager *manager,
358 EmpathyContactManagerPriv *priv;
359 EmpathyTpContactList *list;
361 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
362 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
364 priv = GET_PRIV (manager);
366 list = g_hash_table_lookup (priv->lists, account);
372 return empathy_tp_contact_list_get_user (list);
376 empathy_contact_manager_create (EmpathyContactManager *manager,
380 EmpathyContactManagerPriv *priv;
381 EmpathyTpContactList *list;
383 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
384 g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
385 g_return_val_if_fail (id != NULL, NULL);
387 priv = GET_PRIV (manager);
389 list = g_hash_table_lookup (priv->lists, account);
395 return empathy_tp_contact_list_get_from_id (list, id);
399 empathy_contact_manager_rename_group (EmpathyContactManager *manager,
400 const gchar *old_group,
401 const gchar *new_group)
403 EmpathyContactManagerPriv *priv;
404 ContactManagerRenameGroupData data;
406 g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
407 g_return_if_fail (old_group != NULL);
408 g_return_if_fail (new_group != NULL);
410 priv = GET_PRIV (manager);
412 data.old_group = old_group;
413 data.new_group = new_group;
415 g_hash_table_foreach (priv->lists,
416 (GHFunc) contact_manager_rename_group_foreach,
421 empathy_contact_manager_get_groups (EmpathyContactManager *manager)
423 EmpathyContactManagerPriv *priv;
424 GList *groups = NULL;
426 g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
428 priv = GET_PRIV (manager);
430 g_hash_table_foreach (priv->lists,
431 (GHFunc) contact_manager_get_groups_foreach,
438 contact_manager_setup_foreach (McAccount *account,
439 EmpathyTpContactList *list,
440 EmpathyContactManager *manager)
442 empathy_contact_list_setup (EMPATHY_CONTACT_LIST (list));
446 contact_manager_find_foreach (McAccount *account,
447 EmpathyTpContactList *list,
448 ContactManagerFindData *data)
450 data->contact = empathy_contact_list_find (EMPATHY_CONTACT_LIST (list),
461 contact_manager_add_account (EmpathyContactManager *manager,
464 EmpathyContactManagerPriv *priv;
465 EmpathyTpContactList *list;
467 priv = GET_PRIV (manager);
469 if (g_hash_table_lookup (priv->lists, account)) {
473 empathy_debug (DEBUG_DOMAIN, "Adding new account: %s",
474 mc_account_get_display_name (account));
476 list = empathy_tp_contact_list_new (account);
481 g_hash_table_insert (priv->lists, g_object_ref (account), list);
483 /* Connect signals */
484 g_signal_connect (list, "contact-added",
485 G_CALLBACK (contact_manager_added_cb),
487 g_signal_connect (list, "contact-removed",
488 G_CALLBACK (contact_manager_removed_cb),
490 g_signal_connect (list, "local-pending",
491 G_CALLBACK (contact_manager_local_pending_cb),
493 g_signal_connect (list, "destroy",
494 G_CALLBACK (contact_manager_destroy_cb),
498 empathy_contact_list_setup (EMPATHY_CONTACT_LIST (list));
503 contact_manager_added_cb (EmpathyTpContactList *list,
504 EmpathyContact *contact,
505 EmpathyContactManager *manager)
507 g_signal_emit_by_name (manager, "contact-added", contact);
511 contact_manager_removed_cb (EmpathyTpContactList *list,
512 EmpathyContact *contact,
513 EmpathyContactManager *manager)
515 g_signal_emit_by_name (manager, "contact-removed", contact);
519 contact_manager_local_pending_cb (EmpathyTpContactList *list,
520 EmpathyContact *contact,
521 const gchar *message,
522 EmpathyContactManager *manager)
524 g_signal_emit_by_name (manager, "local-pending", contact, message);
528 contact_manager_destroy_cb (EmpathyTpContactList *list,
529 EmpathyContactManager *manager)
531 EmpathyContactManagerPriv *priv;
534 priv = GET_PRIV (manager);
536 account = empathy_tp_contact_list_get_account (list);
538 empathy_debug (DEBUG_DOMAIN, "Removing account: %s",
539 mc_account_get_display_name (account));
541 /* Disconnect signals from the list */
542 g_signal_handlers_disconnect_by_func (list,
543 contact_manager_added_cb,
545 g_signal_handlers_disconnect_by_func (list,
546 contact_manager_removed_cb,
548 g_signal_handlers_disconnect_by_func (list,
549 contact_manager_local_pending_cb,
551 g_signal_handlers_disconnect_by_func (list,
552 contact_manager_destroy_cb,
555 g_hash_table_remove (priv->lists, account);
559 contact_manager_rename_group_foreach (McAccount *account,
560 EmpathyTpContactList *list,
561 ContactManagerRenameGroupData *data)
563 empathy_tp_contact_list_rename_group (list,
569 contact_manager_get_groups_foreach (McAccount *account,
570 EmpathyTpContactList *list,
575 groups = empathy_tp_contact_list_get_groups (list);
576 for (l = groups; l; l = l->next) {
577 if (!g_list_find_custom (*all_groups,
579 (GCompareFunc) strcmp)) {
580 *all_groups = g_list_append (*all_groups,
586 g_list_free (groups);
590 contact_manager_get_members_foreach (McAccount *account,
591 EmpathyTpContactList *list,
596 l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list));
597 *contacts = g_list_concat (*contacts, l);
601 contact_manager_get_local_pending_foreach (McAccount *account,
602 EmpathyTpContactList *list,
607 l = empathy_contact_list_get_local_pending (EMPATHY_CONTACT_LIST (list));
608 *contacts = g_list_concat (*contacts, l);
612 contact_manager_status_changed_cb (MissionControl *mc,
613 TelepathyConnectionStatus status,
615 TelepathyConnectionStatusReason reason,
616 const gchar *unique_name,
617 EmpathyContactManager *manager)
619 EmpathyContactManagerPriv *priv;
622 priv = GET_PRIV (manager);
624 if (status != TP_CONN_STATUS_CONNECTED) {
625 /* We only care about newly connected accounts */
629 account = mc_account_lookup (unique_name);
630 contact_manager_add_account (manager, account);
632 g_object_unref (account);