]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact-manager.c
If the RequestAliases fails, make sure the name property on all contacts becomes...
[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 #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         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         empathy_debug (DEBUG_DOMAIN, "Removing account: %s",
125                        mc_account_get_display_name (account));
126
127         contact_manager_disconnect_foreach (account, list, manager);
128         g_hash_table_remove (priv->lists, account);
129 }
130
131 static void
132 contact_manager_add_account (EmpathyContactManager *manager,
133                              McAccount             *account)
134 {
135         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
136         EmpathyTpContactList      *list;
137
138         if (g_hash_table_lookup (priv->lists, account)) {
139                 return;
140         }
141
142         empathy_debug (DEBUG_DOMAIN, "Adding new account: %s",
143                        mc_account_get_display_name (account));
144
145         list = empathy_tp_contact_list_new (account);
146         if (!list) {
147                 return;
148         }
149
150         g_hash_table_insert (priv->lists, g_object_ref (account), list);
151
152         /* Connect signals */
153         g_signal_connect (list, "members-changed",
154                           G_CALLBACK (contact_manager_members_changed_cb),
155                           manager);
156         g_signal_connect (list, "pendings-changed",
157                           G_CALLBACK (contact_manager_pendings_changed_cb),
158                           manager);
159         g_signal_connect (list, "groups-changed",
160                           G_CALLBACK (contact_manager_groups_changed_cb),
161                           manager);
162         g_signal_connect (list, "destroy",
163                           G_CALLBACK (contact_manager_destroy_cb),
164                           manager);
165 }
166
167 static void
168 contact_manager_status_changed_cb (MissionControl           *mc,
169                                    TpConnectionStatus        status,
170                                    McPresence                presence,
171                                    TpConnectionStatusReason  reason,
172                                    const gchar              *unique_name,
173                                    EmpathyContactManager    *manager)
174 {
175         McAccount *account;
176
177         if (status != TP_CONNECTION_STATUS_CONNECTED) {
178                 /* We only care about newly connected accounts */
179                 return;
180         }
181
182         account = mc_account_lookup (unique_name);
183         contact_manager_add_account (manager, account);
184         g_object_unref (account);
185 }
186
187 static void
188 contact_manager_finalize (GObject *object)
189 {
190         EmpathyContactManagerPriv *priv = GET_PRIV (object);
191
192         empathy_disconnect_account_status_changed (priv->token);
193         g_hash_table_foreach (priv->lists,
194                               contact_manager_disconnect_foreach,
195                               object);
196         g_hash_table_destroy (priv->lists);
197         g_object_unref (priv->mc);
198 }
199
200 static void
201 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
202 {
203         GObjectClass *object_class = G_OBJECT_CLASS (klass);
204
205         object_class->finalize = contact_manager_finalize;
206
207         g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
208 }
209
210 static void
211 empathy_contact_manager_init (EmpathyContactManager *manager)
212 {
213         EmpathyContactManagerPriv *priv;
214         GSList                    *accounts, *l;
215
216         priv = GET_PRIV (manager);
217
218         priv->lists = g_hash_table_new_full (empathy_account_hash,
219                                              empathy_account_equal,
220                                              (GDestroyNotify) g_object_unref,
221                                              (GDestroyNotify) g_object_unref);
222
223         priv->mc = empathy_mission_control_new ();
224         priv->token = empathy_connect_to_account_status_changed (priv->mc,
225                 G_CALLBACK (contact_manager_status_changed_cb),
226                 manager, NULL);
227
228         /* Get ContactList for existing connections */
229         accounts = mission_control_get_online_connections (priv->mc, NULL);
230         for (l = accounts; l; l = l->next) {
231                 contact_manager_add_account (manager, l->data);
232                 g_object_unref (l->data);
233         }
234         g_slist_free (accounts);
235 }
236
237 EmpathyContactManager *
238 empathy_contact_manager_new (void)
239 {
240         static EmpathyContactManager *manager = NULL;
241
242         if (!manager) {
243                 manager = g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
244                 g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
245         } else {
246                 g_object_ref (manager);
247         }
248
249         return manager;
250 }
251
252 EmpathyTpContactList *
253 empathy_contact_manager_get_list (EmpathyContactManager *manager,
254                                   McAccount             *account)
255 {
256         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
257
258         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
259         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
260
261         return g_hash_table_lookup (priv->lists, account);
262 }
263
264 static void
265 contact_manager_add (EmpathyContactList *manager,
266                      EmpathyContact     *contact,
267                      const gchar        *message)
268 {
269         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
270         EmpathyContactList        *list;
271         McAccount                 *account;
272
273         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
274
275         account = empathy_contact_get_account (contact);
276         list = g_hash_table_lookup (priv->lists, account);
277
278         if (list) {
279                 empathy_contact_list_add (list, contact, message);
280         }
281 }
282
283 static void
284 contact_manager_remove (EmpathyContactList *manager,
285                         EmpathyContact      *contact,
286                         const gchar        *message)
287 {
288         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
289         EmpathyContactList        *list;
290         McAccount                 *account;
291
292         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
293
294         account = empathy_contact_get_account (contact);
295         list = g_hash_table_lookup (priv->lists, account);
296
297         if (list) {
298                 empathy_contact_list_remove (list, contact, message);
299         }
300 }
301
302 static void
303 contact_manager_get_members_foreach (McAccount             *account,
304                                      EmpathyTpContactList  *list,
305                                      GList                **contacts)
306 {
307         GList *l;
308
309         l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list));
310         *contacts = g_list_concat (*contacts, l);
311 }
312
313 static GList *
314 contact_manager_get_members (EmpathyContactList *manager)
315 {
316         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
317         GList                     *contacts = NULL;
318
319         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
320
321         g_hash_table_foreach (priv->lists,
322                               (GHFunc) contact_manager_get_members_foreach,
323                               &contacts);
324
325         return contacts;
326 }
327
328 static void
329 contact_manager_get_pendings_foreach (McAccount             *account,
330                                       EmpathyTpContactList  *list,
331                                       GList                **contacts)
332 {
333         GList *l;
334
335         l = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (list));
336         *contacts = g_list_concat (*contacts, l);
337 }
338
339 static GList *
340 contact_manager_get_pendings (EmpathyContactList *manager)
341 {
342         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
343         GList                     *contacts = NULL;
344
345         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
346
347         g_hash_table_foreach (priv->lists,
348                               (GHFunc) contact_manager_get_pendings_foreach,
349                               &contacts);
350
351         return contacts;
352 }
353
354 static void
355 contact_manager_get_all_groups_foreach (McAccount             *account,
356                                         EmpathyTpContactList  *list,
357                                         GList                **all_groups)
358 {
359         GList *groups, *l;
360
361         groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (list));
362         for (l = groups; l; l = l->next) {
363                 if (!g_list_find_custom (*all_groups,
364                                          l->data,
365                                          (GCompareFunc) strcmp)) {
366                         *all_groups = g_list_prepend (*all_groups, l->data);
367                 } else {
368                         g_free (l->data);
369                 }
370         }
371
372         g_list_free (groups);
373 }
374
375 static GList *
376 contact_manager_get_all_groups (EmpathyContactList *manager)
377 {
378         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
379         GList                     *groups = NULL;
380
381         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
382
383         g_hash_table_foreach (priv->lists,
384                               (GHFunc) contact_manager_get_all_groups_foreach,
385                               &groups);
386
387         return groups;
388 }
389
390 static GList *
391 contact_manager_get_groups (EmpathyContactList *manager,
392                             EmpathyContact     *contact)
393 {
394         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
395         EmpathyContactList        *list;
396         McAccount                 *account;
397
398         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
399
400         account = empathy_contact_get_account (contact);
401         list = g_hash_table_lookup (priv->lists, account);
402
403         if (list) {
404                 return empathy_contact_list_get_groups (list, contact);
405         }
406
407         return NULL;
408 }
409
410 static void
411 contact_manager_add_to_group (EmpathyContactList *manager,
412                               EmpathyContact     *contact,
413                               const gchar        *group)
414 {
415         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
416         EmpathyContactList        *list;
417         McAccount                 *account;
418
419         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
420
421         account = empathy_contact_get_account (contact);
422         list = g_hash_table_lookup (priv->lists, account);
423
424         if (list) {
425                 empathy_contact_list_add_to_group (list, contact, group);
426         }
427 }
428
429 static void
430 contact_manager_remove_from_group (EmpathyContactList *manager,
431                                    EmpathyContact     *contact,
432                                    const gchar        *group)
433 {
434         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
435         EmpathyContactList        *list;
436         McAccount                 *account;
437
438         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
439
440         account = empathy_contact_get_account (contact);
441         list = g_hash_table_lookup (priv->lists, account);
442
443         if (list) {
444                 empathy_contact_list_remove_from_group (list, contact, group);
445         }
446 }
447
448 typedef struct {
449         const gchar *old_group;
450         const gchar *new_group;
451 } RenameGroupData;
452
453 static void
454 contact_manager_rename_group_foreach (McAccount            *account,
455                                       EmpathyTpContactList *list,
456                                       RenameGroupData      *data)
457 {
458         empathy_contact_list_rename_group (EMPATHY_CONTACT_LIST (list),
459                                            data->old_group,
460                                            data->new_group);
461 }
462
463 static void
464 contact_manager_rename_group (EmpathyContactList *manager,
465                               const gchar        *old_group,
466                               const gchar        *new_group)
467 {
468         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
469         RenameGroupData            data;
470
471         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
472
473         data.old_group = old_group;
474         data.new_group = new_group;
475         g_hash_table_foreach (priv->lists,
476                               (GHFunc) contact_manager_rename_group_foreach,
477                               &data);
478 }
479
480 static void contact_manager_remove_group_foreach (McAccount     *account,
481                                                   EmpathyTpContactList *list,
482                                                   const gchar *group)
483 {
484         empathy_contact_list_remove_group (EMPATHY_CONTACT_LIST (list),
485                                            group);
486 }
487
488 static void
489 contact_manager_remove_group (EmpathyContactList *manager,
490                               const gchar *group)
491 {
492         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
493         
494         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
495
496         g_hash_table_foreach (priv->lists,
497                               (GHFunc) contact_manager_remove_group_foreach,
498                               (gpointer) group);
499 }
500
501 static void
502 contact_manager_iface_init (EmpathyContactListIface *iface)
503 {
504         iface->add               = contact_manager_add;
505         iface->remove            = contact_manager_remove;
506         iface->get_members       = contact_manager_get_members;
507         iface->get_pendings      = contact_manager_get_pendings;
508         iface->get_all_groups    = contact_manager_get_all_groups;
509         iface->get_groups        = contact_manager_get_groups;
510         iface->add_to_group      = contact_manager_add_to_group;
511         iface->remove_from_group = contact_manager_remove_from_group;
512         iface->rename_group      = contact_manager_rename_group;
513         iface->remove_group      = contact_manager_remove_group;
514 }
515