]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact-manager.c
Merge commit 'jtellier/video-call-button-sensitivity'
[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-account-manager.h"
30 #include "empathy-contact-monitor.h"
31 #include "empathy-contact-list.h"
32 #include "empathy-utils.h"
33
34 #define DEBUG_FLAG EMPATHY_DEBUG_CONTACT
35 #include "empathy-debug.h"
36
37 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyContactManager)
38 typedef struct {
39         GHashTable     *lists;
40         EmpathyAccountManager *account_manager;
41         EmpathyContactMonitor *contact_monitor;
42 } EmpathyContactManagerPriv;
43
44 static void contact_manager_iface_init         (EmpathyContactListIface    *iface);
45
46 G_DEFINE_TYPE_WITH_CODE (EmpathyContactManager, empathy_contact_manager, G_TYPE_OBJECT,
47                          G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
48                                                 contact_manager_iface_init));
49
50 static EmpathyContactManager *manager_singleton = NULL;
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
90 contact_manager_invalidated_cb (TpProxy *connection,
91                                 guint    domain,
92                                 gint     code,
93                                 gchar   *message,
94                                 EmpathyContactManager *manager)
95 {
96         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
97         EmpathyTpContactList *list;
98
99         DEBUG ("Removing connection: %s (%s)",
100                 tp_proxy_get_object_path (TP_PROXY (connection)),
101                 message);
102
103         list = g_hash_table_lookup (priv->lists, connection);
104         if (list) {
105                 empathy_tp_contact_list_remove_all (list);
106                 g_hash_table_remove (priv->lists, connection);
107         }
108 }
109
110 static void
111 contact_manager_disconnect_foreach (gpointer key,
112                                     gpointer value,
113                                     gpointer user_data)
114 {
115         TpConnection *connection = key;
116         EmpathyTpContactList  *list = value;
117         EmpathyContactManager *manager = user_data;
118
119         /* Disconnect signals from the list */
120         g_signal_handlers_disconnect_by_func (list,
121                                               contact_manager_members_changed_cb,
122                                               manager);
123         g_signal_handlers_disconnect_by_func (list,
124                                               contact_manager_pendings_changed_cb,
125                                               manager);
126         g_signal_handlers_disconnect_by_func (list,
127                                               contact_manager_groups_changed_cb,
128                                               manager);
129         g_signal_handlers_disconnect_by_func (connection,
130                                               contact_manager_invalidated_cb,
131                                               manager);
132 }
133
134 static void
135 contact_manager_new_connection_cb (EmpathyAccountManager *account_manager,
136                                    TpConnection *connection,
137                                    EmpathyContactManager *self)
138 {
139         EmpathyContactManagerPriv *priv = GET_PRIV (self);
140         EmpathyTpContactList      *list;
141
142         if (g_hash_table_lookup (priv->lists, connection)) {
143                 return;
144         }
145
146         DEBUG ("Adding new connection: %s",
147                 tp_proxy_get_object_path (TP_PROXY (connection)));
148
149         list = empathy_tp_contact_list_new (connection);
150         g_hash_table_insert (priv->lists, g_object_ref (connection), list);
151         g_signal_connect (connection, "invalidated",
152                           G_CALLBACK (contact_manager_invalidated_cb),
153                           self);
154
155         /* Connect signals */
156         g_signal_connect (list, "members-changed",
157                           G_CALLBACK (contact_manager_members_changed_cb),
158                           self);
159         g_signal_connect (list, "pendings-changed",
160                           G_CALLBACK (contact_manager_pendings_changed_cb),
161                           self);
162         g_signal_connect (list, "groups-changed",
163                           G_CALLBACK (contact_manager_groups_changed_cb),
164                           self);
165 }
166
167 static void
168 contact_manager_finalize (GObject *object)
169 {
170         EmpathyContactManagerPriv *priv = GET_PRIV (object);
171
172         g_hash_table_foreach (priv->lists,
173                               contact_manager_disconnect_foreach,
174                               object);
175         g_hash_table_destroy (priv->lists);
176
177         g_signal_handlers_disconnect_by_func (priv->account_manager,
178                                               contact_manager_new_connection_cb,
179                                               object);
180         g_object_unref (priv->account_manager);
181
182         if (priv->contact_monitor) {
183                 g_object_unref (priv->contact_monitor);
184         }
185 }
186
187 static GObject *
188 contact_manager_constructor (GType type,
189                              guint n_props,
190                              GObjectConstructParam *props)
191 {
192         GObject *retval;
193
194         if (manager_singleton) {
195                 retval = g_object_ref (manager_singleton);
196         } else {
197                 retval = G_OBJECT_CLASS (empathy_contact_manager_parent_class)->constructor
198                         (type, n_props, props);
199
200                 manager_singleton = EMPATHY_CONTACT_MANAGER (retval);
201                 g_object_add_weak_pointer (retval, (gpointer) &manager_singleton);
202         }
203
204         return retval;
205 }
206
207 /**
208  * empathy_contact_manager_initialized:
209  *
210  * Reports whether or not the singleton has already been created.
211  *
212  * There can be instances where you want to access the #EmpathyContactManager
213  * only if it has been set up for this process.
214  *
215  * Returns: %TRUE if the #EmpathyContactManager singleton has previously
216  * been initialized.
217  */
218 gboolean
219 empathy_contact_manager_initialized (void)
220 {
221         return (manager_singleton != NULL);
222 }
223
224 static void
225 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
226 {
227         GObjectClass *object_class = G_OBJECT_CLASS (klass);
228
229         object_class->finalize = contact_manager_finalize;
230         object_class->constructor = contact_manager_constructor;
231
232         g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
233 }
234
235 static void
236 empathy_contact_manager_init (EmpathyContactManager *manager)
237 {
238         GList *connections, *l;
239         EmpathyContactManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
240                 EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv);
241
242         manager->priv = priv;
243         priv->lists = g_hash_table_new_full (empathy_proxy_hash,
244                                              empathy_proxy_equal,
245                                              (GDestroyNotify) g_object_unref,
246                                              (GDestroyNotify) g_object_unref);
247         priv->account_manager = empathy_account_manager_dup_singleton ();
248         priv->contact_monitor = NULL;
249
250         g_signal_connect (priv->account_manager, "new-connection",
251                           G_CALLBACK (contact_manager_new_connection_cb),
252                           manager);
253
254         /* Get ContactList for existing connections */
255         connections = empathy_account_manager_dup_connections (priv->account_manager);
256         for (l = connections; l; l = l->next) {
257                 contact_manager_new_connection_cb (priv->account_manager,
258                                                    l->data, manager);
259                 g_object_unref (l->data);
260         }
261         g_list_free (connections);
262 }
263
264 EmpathyContactManager *
265 empathy_contact_manager_dup_singleton (void)
266 {
267         return g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
268 }
269
270 EmpathyTpContactList *
271 empathy_contact_manager_get_list (EmpathyContactManager *manager,
272                                   TpConnection          *connection)
273 {
274         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
275
276         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
277         g_return_val_if_fail (TP_IS_CONNECTION (connection), NULL);
278
279         return g_hash_table_lookup (priv->lists, connection);
280 }
281
282 static void
283 contact_manager_add (EmpathyContactList *manager,
284                      EmpathyContact     *contact,
285                      const gchar        *message)
286 {
287         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
288         EmpathyContactList        *list;
289         TpConnection              *connection;
290
291         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
292
293         connection = empathy_contact_get_connection (contact);
294         list = g_hash_table_lookup (priv->lists, connection);
295
296         if (list) {
297                 empathy_contact_list_add (list, contact, message);
298         }
299 }
300
301 static void
302 contact_manager_remove (EmpathyContactList *manager,
303                         EmpathyContact     *contact,
304                         const gchar        *message)
305 {
306         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
307         EmpathyContactList        *list;
308         TpConnection              *connection;
309
310         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
311
312         connection = empathy_contact_get_connection (contact);
313         list = g_hash_table_lookup (priv->lists, connection);
314
315         if (list) {
316                 empathy_contact_list_remove (list, contact, message);
317         }
318 }
319
320 static void
321 contact_manager_get_members_foreach (TpConnection          *connection,
322                                      EmpathyTpContactList  *list,
323                                      GList                **contacts)
324 {
325         GList *l;
326
327         l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list));
328         *contacts = g_list_concat (*contacts, l);
329 }
330
331 static GList *
332 contact_manager_get_members (EmpathyContactList *manager)
333 {
334         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
335         GList                     *contacts = NULL;
336
337         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
338
339         g_hash_table_foreach (priv->lists,
340                               (GHFunc) contact_manager_get_members_foreach,
341                               &contacts);
342
343         return contacts;
344 }
345
346 static EmpathyContactMonitor *
347 contact_manager_get_monitor (EmpathyContactList *manager)
348 {
349         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
350
351         if (priv->contact_monitor == NULL) {
352                 priv->contact_monitor = empathy_contact_monitor_new_for_iface (manager);
353         }
354
355         return priv->contact_monitor;
356 }
357
358 static void
359 contact_manager_get_pendings_foreach (TpConnection          *connection,
360                                       EmpathyTpContactList  *list,
361                                       GList                **contacts)
362 {
363         GList *l;
364
365         l = empathy_contact_list_get_pendings (EMPATHY_CONTACT_LIST (list));
366         *contacts = g_list_concat (*contacts, l);
367 }
368
369 static GList *
370 contact_manager_get_pendings (EmpathyContactList *manager)
371 {
372         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
373         GList                     *contacts = 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_pendings_foreach,
379                               &contacts);
380
381         return contacts;
382 }
383
384 static void
385 contact_manager_get_all_groups_foreach (TpConnection          *connection,
386                                         EmpathyTpContactList  *list,
387                                         GList                **all_groups)
388 {
389         GList *groups, *l;
390
391         groups = empathy_contact_list_get_all_groups (EMPATHY_CONTACT_LIST (list));
392         for (l = groups; l; l = l->next) {
393                 if (!g_list_find_custom (*all_groups,
394                                          l->data,
395                                          (GCompareFunc) strcmp)) {
396                         *all_groups = g_list_prepend (*all_groups, l->data);
397                 } else {
398                         g_free (l->data);
399                 }
400         }
401
402         g_list_free (groups);
403 }
404
405 static GList *
406 contact_manager_get_all_groups (EmpathyContactList *manager)
407 {
408         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
409         GList                     *groups = NULL;
410
411         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
412
413         g_hash_table_foreach (priv->lists,
414                               (GHFunc) contact_manager_get_all_groups_foreach,
415                               &groups);
416
417         return groups;
418 }
419
420 static GList *
421 contact_manager_get_groups (EmpathyContactList *manager,
422                             EmpathyContact     *contact)
423 {
424         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
425         EmpathyContactList        *list;
426         TpConnection              *connection;
427
428         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
429
430         connection = empathy_contact_get_connection (contact);
431         list = g_hash_table_lookup (priv->lists, connection);
432
433         if (list) {
434                 return empathy_contact_list_get_groups (list, contact);
435         }
436
437         return NULL;
438 }
439
440 static void
441 contact_manager_add_to_group (EmpathyContactList *manager,
442                               EmpathyContact     *contact,
443                               const gchar        *group)
444 {
445         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
446         EmpathyContactList        *list;
447         TpConnection              *connection;
448
449         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
450
451         connection = empathy_contact_get_connection (contact);
452         list = g_hash_table_lookup (priv->lists, connection);
453
454         if (list) {
455                 empathy_contact_list_add_to_group (list, contact, group);
456         }
457 }
458
459 static void
460 contact_manager_remove_from_group (EmpathyContactList *manager,
461                                    EmpathyContact     *contact,
462                                    const gchar        *group)
463 {
464         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
465         EmpathyContactList        *list;
466         TpConnection              *connection;
467
468         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
469
470         connection = empathy_contact_get_connection (contact);
471         list = g_hash_table_lookup (priv->lists, connection);
472
473         if (list) {
474                 empathy_contact_list_remove_from_group (list, contact, group);
475         }
476 }
477
478 typedef struct {
479         const gchar *old_group;
480         const gchar *new_group;
481 } RenameGroupData;
482
483 static void
484 contact_manager_rename_group_foreach (TpConnection         *connection,
485                                       EmpathyTpContactList *list,
486                                       RenameGroupData      *data)
487 {
488         empathy_contact_list_rename_group (EMPATHY_CONTACT_LIST (list),
489                                            data->old_group,
490                                            data->new_group);
491 }
492
493 static void
494 contact_manager_rename_group (EmpathyContactList *manager,
495                               const gchar        *old_group,
496                               const gchar        *new_group)
497 {
498         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
499         RenameGroupData            data;
500
501         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
502
503         data.old_group = old_group;
504         data.new_group = new_group;
505         g_hash_table_foreach (priv->lists,
506                               (GHFunc) contact_manager_rename_group_foreach,
507                               &data);
508 }
509
510 static void contact_manager_remove_group_foreach (TpConnection         *connection,
511                                                   EmpathyTpContactList *list,
512                                                   const gchar *group)
513 {
514         empathy_contact_list_remove_group (EMPATHY_CONTACT_LIST (list),
515                                            group);
516 }
517
518 static void
519 contact_manager_remove_group (EmpathyContactList *manager,
520                               const gchar *group)
521 {
522         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
523
524         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
525
526         g_hash_table_foreach (priv->lists,
527                               (GHFunc) contact_manager_remove_group_foreach,
528                               (gpointer) group);
529 }
530
531 static void
532 contact_manager_iface_init (EmpathyContactListIface *iface)
533 {
534         iface->add               = contact_manager_add;
535         iface->remove            = contact_manager_remove;
536         iface->get_members       = contact_manager_get_members;
537         iface->get_monitor       = contact_manager_get_monitor;
538         iface->get_pendings      = contact_manager_get_pendings;
539         iface->get_all_groups    = contact_manager_get_all_groups;
540         iface->get_groups        = contact_manager_get_groups;
541         iface->add_to_group      = contact_manager_add_to_group;
542         iface->remove_from_group = contact_manager_remove_from_group;
543         iface->rename_group      = contact_manager_rename_group;
544         iface->remove_group      = contact_manager_remove_group;
545 }
546
547 EmpathyContactListFlags
548 empathy_contact_manager_get_flags_for_connection (
549                                 EmpathyContactManager *manager,
550                                 TpConnection          *connection)
551 {
552         EmpathyContactManagerPriv *priv = GET_PRIV (manager);
553         EmpathyContactList        *list;
554         EmpathyContactListFlags    flags;
555
556         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), FALSE);
557         g_return_val_if_fail (connection != NULL, FALSE);
558
559         list = g_hash_table_lookup (priv->lists, connection);
560         if (list == NULL) {
561                 return FALSE;
562         }
563         flags = empathy_contact_list_get_flags (list);
564
565         return flags;
566 }
567