]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact-manager.c
Make use of tp-glib debug system.
[empathy.git] / libempathy / empathy-contact-manager.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2007-2008 Collabora Ltd.
4  *
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.
9  *
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.
14  *
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
18  * 
19  * Authors: Xavier Claessens <xclaesse@gmail.com>
20  */
21
22 #include <config.h>
23
24 #include <string.h>
25
26 #include <telepathy-glib/enums.h>
27
28 #include "empathy-contact-manager.h"
29 #include "empathy-contact-list.h"
30 #include "empathy-utils.h"
31
32 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
33 #include "empathy-debug.h"
34
35 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
36                        EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv))
37
38 struct _EmpathyContactManagerPriv {
39         GHashTable     *lists;
40         MissionControl *mc;
41         gpointer        token;
42 };
43
44 static void empathy_contact_manager_class_init (EmpathyContactManagerClass *klass);
45 static void empathy_contact_manager_init       (EmpathyContactManager      *manager);
46 static void contact_manager_iface_init         (EmpathyContactListIface    *iface);
47
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));
51
52 static void
53 contact_manager_members_changed_cb (EmpathyTpContactList  *list,
54                                     EmpathyContact        *contact,
55                                     EmpathyContact        *actor,
56                                     guint                  reason,
57                                     gchar                 *message,
58                                     gboolean               is_member,
59                                     EmpathyContactManager *manager)
60 {
61         g_signal_emit_by_name (manager, "members-changed",
62                                contact, actor, reason, message, is_member);
63 }
64
65 static void
66 contact_manager_pendings_changed_cb (EmpathyTpContactList  *list,
67                                      EmpathyContact        *contact,
68                                      EmpathyContact        *actor,
69                                      guint                  reason,
70                                      gchar                 *message,
71                                      gboolean               is_pending,
72                                      EmpathyContactManager *manager)
73 {
74         g_signal_emit_by_name (manager, "pendings-changed",
75                                contact, actor, reason, message, is_pending);
76 }
77
78 static void
79 contact_manager_groups_changed_cb (EmpathyTpContactList  *list,
80                                    EmpathyContact        *contact,
81                                    gchar                 *group,
82                                    gboolean               is_member,
83                                    EmpathyContactManager *manager)
84 {
85         g_signal_emit_by_name (manager, "groups-changed",
86                                contact, group, is_member);
87 }
88
89 static void contact_manager_destroy_cb (EmpathyTpContactList  *list,
90                                         EmpathyContactManager *manager);
91
92 static void
93 contact_manager_disconnect_foreach (gpointer key,
94                                     gpointer value,
95                                     gpointer user_data)
96 {
97         EmpathyTpContactList  *list = value;
98         EmpathyContactManager *manager = user_data;
99
100         /* Disconnect signals from the list */
101         g_signal_handlers_disconnect_by_func (list,
102                                               contact_manager_members_changed_cb,
103                                               manager);
104         g_signal_handlers_disconnect_by_func (list,
105                                               contact_manager_pendings_changed_cb,
106                                               manager);
107         g_signal_handlers_disconnect_by_func (list,
108                                               contact_manager_groups_changed_cb,
109                                               manager);
110         g_signal_handlers_disconnect_by_func (list,
111                                               contact_manager_destroy_cb,
112                                               manager);
113 }
114
115 static void
116 contact_manager_destroy_cb (EmpathyTpContactList  *list,
117                             EmpathyContactManager *manager)
118 {
119         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
120         McAccount                 *account;
121
122         account = empathy_tp_contact_list_get_account (list);
123
124         DEBUG ("Removing account: %s", mc_account_get_display_name (account));
125
126         contact_manager_disconnect_foreach (account, list, manager);
127         g_hash_table_remove (priv->lists, account);
128 }
129
130 static void
131 contact_manager_add_account (EmpathyContactManager *manager,
132                              McAccount             *account)
133 {
134         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
135         EmpathyTpContactList      *list;
136
137         if (g_hash_table_lookup (priv->lists, account)) {
138                 return;
139         }
140
141         DEBUG ("Adding new account: %s", mc_account_get_display_name (account));
142
143         list = empathy_tp_contact_list_new (account);
144         if (!list) {
145                 return;
146         }
147
148         g_hash_table_insert (priv->lists, g_object_ref (account), list);
149
150         /* Connect signals */
151         g_signal_connect (list, "members-changed",
152                           G_CALLBACK (contact_manager_members_changed_cb),
153                           manager);
154         g_signal_connect (list, "pendings-changed",
155                           G_CALLBACK (contact_manager_pendings_changed_cb),
156                           manager);
157         g_signal_connect (list, "groups-changed",
158                           G_CALLBACK (contact_manager_groups_changed_cb),
159                           manager);
160         g_signal_connect (list, "destroy",
161                           G_CALLBACK (contact_manager_destroy_cb),
162                           manager);
163 }
164
165 static void
166 contact_manager_status_changed_cb (MissionControl           *mc,
167                                    TpConnectionStatus        status,
168                                    McPresence                presence,
169                                    TpConnectionStatusReason  reason,
170                                    const gchar              *unique_name,
171                                    EmpathyContactManager    *manager)
172 {
173         McAccount *account;
174
175         if (status != TP_CONNECTION_STATUS_CONNECTED) {
176                 /* We only care about newly connected accounts */
177                 return;
178         }
179
180         account = mc_account_lookup (unique_name);
181         contact_manager_add_account (manager, account);
182         g_object_unref (account);
183 }
184
185 static void
186 contact_manager_finalize (GObject *object)
187 {
188         EmpathyContactManagerPriv *priv = GET_PRIV (object);
189
190         empathy_disconnect_account_status_changed (priv->token);
191         g_hash_table_foreach (priv->lists,
192                               contact_manager_disconnect_foreach,
193                               object);
194         g_hash_table_destroy (priv->lists);
195         g_object_unref (priv->mc);
196 }
197
198 static void
199 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
200 {
201         GObjectClass *object_class = G_OBJECT_CLASS (klass);
202
203         object_class->finalize = contact_manager_finalize;
204
205         g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
206 }
207
208 static void
209 empathy_contact_manager_init (EmpathyContactManager *manager)
210 {
211         EmpathyContactManagerPriv *priv;
212         GSList                    *accounts, *l;
213
214         priv = GET_PRIV (manager);
215
216         priv->lists = g_hash_table_new_full (empathy_account_hash,
217                                              empathy_account_equal,
218                                              (GDestroyNotify) g_object_unref,
219                                              (GDestroyNotify) g_object_unref);
220
221         priv->mc = empathy_mission_control_new ();
222         priv->token = empathy_connect_to_account_status_changed (priv->mc,
223                 G_CALLBACK (contact_manager_status_changed_cb),
224                 manager, NULL);
225
226         /* Get ContactList for existing connections */
227         accounts = mission_control_get_online_connections (priv->mc, NULL);
228         for (l = accounts; l; l = l->next) {
229                 contact_manager_add_account (manager, l->data);
230                 g_object_unref (l->data);
231         }
232         g_slist_free (accounts);
233 }
234
235 EmpathyContactManager *
236 empathy_contact_manager_new (void)
237 {
238         static EmpathyContactManager *manager = NULL;
239
240         if (!manager) {
241                 manager = g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
242                 g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
243         } else {
244                 g_object_ref (manager);
245         }
246
247         return manager;
248 }
249
250 EmpathyTpContactList *
251 empathy_contact_manager_get_list (EmpathyContactManager *manager,
252                                   McAccount             *account)
253 {
254         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
255
256         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
257         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
258
259         return g_hash_table_lookup (priv->lists, account);
260 }
261
262 static void
263 contact_manager_add (EmpathyContactList *manager,
264                      EmpathyContact     *contact,
265                      const gchar        *message)
266 {
267         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
268         EmpathyContactList        *list;
269         McAccount                 *account;
270
271         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
272
273         account = empathy_contact_get_account (contact);
274         list = g_hash_table_lookup (priv->lists, account);
275
276         if (list) {
277                 empathy_contact_list_add (list, contact, message);
278         }
279 }
280
281 static void
282 contact_manager_remove (EmpathyContactList *manager,
283                         EmpathyContact      *contact,
284                         const gchar        *message)
285 {
286         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
287         EmpathyContactList        *list;
288         McAccount                 *account;
289
290         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
291
292         account = empathy_contact_get_account (contact);
293         list = g_hash_table_lookup (priv->lists, account);
294
295         if (list) {
296                 empathy_contact_list_remove (list, contact, message);
297         }
298 }
299
300 static void
301 contact_manager_get_members_foreach (McAccount             *account,
302                                      EmpathyTpContactList  *list,
303                                      GList                **contacts)
304 {
305         GList *l;
306
307         l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list));
308         *contacts = g_list_concat (*contacts, l);
309 }
310
311 static GList *
312 contact_manager_get_members (EmpathyContactList *manager)
313 {
314         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
315         GList                     *contacts = NULL;
316
317         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
318
319         g_hash_table_foreach (priv->lists,
320                               (GHFunc) contact_manager_get_members_foreach,
321                               &contacts);
322
323         return contacts;
324 }
325
326 static void
327 contact_manager_get_pendings_foreach (McAccount             *account,
328                                       EmpathyTpContactList  *list,
329                                       GList                **contacts)
330 {
331         GList *l;
332
333         l = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (list));
334         *contacts = g_list_concat (*contacts, l);
335 }
336
337 static GList *
338 contact_manager_get_pendings (EmpathyContactList *manager)
339 {
340         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
341         GList                     *contacts = NULL;
342
343         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
344
345         g_hash_table_foreach (priv->lists,
346                               (GHFunc) contact_manager_get_pendings_foreach,
347                               &contacts);
348
349         return contacts;
350 }
351
352 static void
353 contact_manager_get_all_groups_foreach (McAccount             *account,
354                                         EmpathyTpContactList  *list,
355                                         GList                **all_groups)
356 {
357         GList *groups, *l;
358
359         groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (list));
360         for (l = groups; l; l = l->next) {
361                 if (!g_list_find_custom (*all_groups,
362                                          l->data,
363                                          (GCompareFunc) strcmp)) {
364                         *all_groups = g_list_prepend (*all_groups, l->data);
365                 } else {
366                         g_free (l->data);
367                 }
368         }
369
370         g_list_free (groups);
371 }
372
373 static GList *
374 contact_manager_get_all_groups (EmpathyContactList *manager)
375 {
376         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
377         GList                     *groups = NULL;
378
379         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
380
381         g_hash_table_foreach (priv->lists,
382                               (GHFunc) contact_manager_get_all_groups_foreach,
383                               &groups);
384
385         return groups;
386 }
387
388 static GList *
389 contact_manager_get_groups (EmpathyContactList *manager,
390                             EmpathyContact     *contact)
391 {
392         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
393         EmpathyContactList        *list;
394         McAccount                 *account;
395
396         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
397
398         account = empathy_contact_get_account (contact);
399         list = g_hash_table_lookup (priv->lists, account);
400
401         if (list) {
402                 return empathy_contact_list_get_groups (list, contact);
403         }
404
405         return NULL;
406 }
407
408 static void
409 contact_manager_add_to_group (EmpathyContactList *manager,
410                               EmpathyContact     *contact,
411                               const gchar        *group)
412 {
413         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
414         EmpathyContactList        *list;
415         McAccount                 *account;
416
417         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
418
419         account = empathy_contact_get_account (contact);
420         list = g_hash_table_lookup (priv->lists, account);
421
422         if (list) {
423                 empathy_contact_list_add_to_group (list, contact, group);
424         }
425 }
426
427 static void
428 contact_manager_remove_from_group (EmpathyContactList *manager,
429                                    EmpathyContact     *contact,
430                                    const gchar        *group)
431 {
432         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
433         EmpathyContactList        *list;
434         McAccount                 *account;
435
436         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
437
438         account = empathy_contact_get_account (contact);
439         list = g_hash_table_lookup (priv->lists, account);
440
441         if (list) {
442                 empathy_contact_list_remove_from_group (list, contact, group);
443         }
444 }
445
446 typedef struct {
447         const gchar *old_group;
448         const gchar *new_group;
449 } RenameGroupData;
450
451 static void
452 contact_manager_rename_group_foreach (McAccount            *account,
453                                       EmpathyTpContactList *list,
454                                       RenameGroupData      *data)
455 {
456         empathy_contact_list_rename_group (EMPATHY_CONTACT_LIST (list),
457                                            data->old_group,
458                                            data->new_group);
459 }
460
461 static void
462 contact_manager_rename_group (EmpathyContactList *manager,
463                               const gchar        *old_group,
464                               const gchar        *new_group)
465 {
466         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
467         RenameGroupData            data;
468
469         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
470
471         data.old_group = old_group;
472         data.new_group = new_group;
473         g_hash_table_foreach (priv->lists,
474                               (GHFunc) contact_manager_rename_group_foreach,
475                               &data);
476 }
477
478 static void contact_manager_remove_group_foreach (McAccount     *account,
479                                                   EmpathyTpContactList *list,
480                                                   const gchar *group)
481 {
482         empathy_contact_list_remove_group (EMPATHY_CONTACT_LIST (list),
483                                            group);
484 }
485
486 static void
487 contact_manager_remove_group (EmpathyContactList *manager,
488                               const gchar *group)
489 {
490         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
491         
492         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
493
494         g_hash_table_foreach (priv->lists,
495                               (GHFunc) contact_manager_remove_group_foreach,
496                               (gpointer) group);
497 }
498
499 static void
500 contact_manager_iface_init (EmpathyContactListIface *iface)
501 {
502         iface->add               = contact_manager_add;
503         iface->remove            = contact_manager_remove;
504         iface->get_members       = contact_manager_get_members;
505         iface->get_pendings      = contact_manager_get_pendings;
506         iface->get_all_groups    = contact_manager_get_all_groups;
507         iface->get_groups        = contact_manager_get_groups;
508         iface->add_to_group      = contact_manager_add_to_group;
509         iface->remove_from_group = contact_manager_remove_from_group;
510         iface->rename_group      = contact_manager_rename_group;
511         iface->remove_group      = contact_manager_remove_group;
512 }
513