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