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