]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact-manager.c
[darcs-to-svn @ gossip_mission_control_new() returns a MissionControl sigleton object...
[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 program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program 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  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26
27 #include <libtelepathy/tp-constants.h>
28
29 #include "empathy-contact-manager.h"
30 #include "gossip-utils.h"
31 #include "gossip-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         gboolean        setup;
42 };
43
44 typedef struct {
45         const gchar *old_group;
46         const gchar *new_group;
47 } ContactManagerRenameGroupData;
48
49 typedef struct {
50         GossipContact *contact;
51         const gchar   *id;
52 } ContactManagerFindData;
53
54 static void     empathy_contact_manager_class_init   (EmpathyContactManagerClass      *klass);
55 static void     empathy_contact_manager_init         (EmpathyContactManager           *manager);
56 static void     contact_manager_finalize             (GObject                         *object);
57 static void     contact_manager_setup_foreach        (McAccount                       *account,
58                                                       EmpathyContactList              *list,
59                                                       EmpathyContactManager           *manager);
60 static gboolean contact_manager_find_foreach         (McAccount                       *account,
61                                                       EmpathyContactList              *list,
62                                                       ContactManagerFindData          *data);
63 static void     contact_manager_add_account          (EmpathyContactManager           *manager,
64                                                       McAccount                       *account);
65 static void     contact_manager_added_cb             (EmpathyContactList              *list,
66                                                       GossipContact                   *contact,
67                                                       EmpathyContactManager           *manager);
68 static void     contact_manager_removed_cb           (EmpathyContactList              *list,
69                                                       GossipContact                   *contact,
70                                                       EmpathyContactManager           *manager);
71 static void     contact_manager_destroy_cb           (EmpathyContactList              *list,
72                                                       EmpathyContactManager           *manager);
73 static void     contact_manager_rename_group_foreach (McAccount                       *account,
74                                                       EmpathyContactList              *list,
75                                                       ContactManagerRenameGroupData   *data);
76 static void     contact_manager_get_groups_foreach   (McAccount                       *account,
77                                                       EmpathyContactList              *list,
78                                                       GList                          **all_groups);
79 static void     contact_manager_get_contacts_foreach (McAccount                       *account,
80                                                       EmpathyContactList              *list,
81                                                       GList                          **contacts);
82 static void     contact_manager_status_changed_cb    (MissionControl                  *mc,
83                                                       TelepathyConnectionStatus        status,
84                                                       McPresence                       presence,
85                                                       TelepathyConnectionStatusReason  reason,
86                                                       const gchar                     *unique_name,
87                                                       EmpathyContactManager           *manager);
88
89 enum {
90         CONTACT_ADDED,
91         CONTACT_REMOVED,
92         LAST_SIGNAL
93 };
94
95 static guint signals[LAST_SIGNAL];
96
97 G_DEFINE_TYPE (EmpathyContactManager, empathy_contact_manager, G_TYPE_OBJECT);
98
99 static void
100 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
101 {
102         GObjectClass *object_class = G_OBJECT_CLASS (klass);
103
104         object_class->finalize = contact_manager_finalize;
105
106         signals[CONTACT_ADDED] =
107                 g_signal_new ("contact-added",
108                               G_TYPE_FROM_CLASS (klass),
109                               G_SIGNAL_RUN_LAST,
110                               0,
111                               NULL, NULL,
112                               g_cclosure_marshal_VOID__OBJECT,
113                               G_TYPE_NONE,
114                               1, GOSSIP_TYPE_CONTACT);
115
116         signals[CONTACT_REMOVED] =
117                 g_signal_new ("contact-removed",
118                               G_TYPE_FROM_CLASS (klass),
119                               G_SIGNAL_RUN_LAST,
120                               0,
121                               NULL, NULL,
122                               g_cclosure_marshal_VOID__OBJECT,
123                               G_TYPE_NONE,
124                               1, GOSSIP_TYPE_CONTACT);
125
126         g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
127 }
128
129 static void
130 empathy_contact_manager_init (EmpathyContactManager *manager)
131 {
132         EmpathyContactManagerPriv *priv;
133         GSList                    *accounts, *l;
134
135         priv = GET_PRIV (manager);
136
137         priv->lists = g_hash_table_new_full (gossip_account_hash,
138                                              gossip_account_equal,
139                                              (GDestroyNotify) g_object_unref,
140                                              (GDestroyNotify) g_object_unref);
141
142         priv->mc = gossip_mission_control_new ();
143
144         dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
145                                      "AccountStatusChanged",
146                                      G_CALLBACK (contact_manager_status_changed_cb),
147                                      manager, NULL);
148
149         /* Get ContactList for existing connections */
150         accounts = mission_control_get_online_connections (priv->mc, NULL);
151         for (l = accounts; l; l = l->next) {
152                 McAccount *account;
153
154                 account = l->data;
155                 contact_manager_add_account (manager, account);
156                 
157                 g_object_unref (account);
158         }
159         g_slist_free (accounts);
160 }
161
162 static void
163 contact_manager_finalize (GObject *object)
164 {
165         EmpathyContactManagerPriv *priv;
166
167         priv = GET_PRIV (object);
168
169         g_hash_table_destroy (priv->lists);
170         g_object_unref (priv->mc);
171 }
172
173 EmpathyContactManager *
174 empathy_contact_manager_new (void)
175 {
176         static EmpathyContactManager *manager = NULL;
177
178         if (!manager) {
179                 manager = g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
180                 g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
181         } else {
182                 g_object_ref (manager);
183         }
184
185         return manager;
186 }
187
188 void
189 empathy_contact_manager_setup (EmpathyContactManager *manager)
190 {
191         EmpathyContactManagerPriv *priv;
192
193         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
194
195         priv = GET_PRIV (manager);
196
197         if (priv->setup) {
198                 /* Already done */
199                 return;
200         }
201
202         g_hash_table_foreach (priv->lists,
203                               (GHFunc) contact_manager_setup_foreach,
204                               manager);
205
206         priv->setup = TRUE;
207 }
208
209 EmpathyContactList *
210 empathy_contact_manager_get_list (EmpathyContactManager *manager,
211                                   McAccount             *account)
212 {
213         EmpathyContactManagerPriv *priv;
214
215         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
216         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
217
218         priv = GET_PRIV (manager);
219
220         return g_hash_table_lookup (priv->lists, account);
221 }
222
223 GossipContact *
224 empathy_contact_manager_get_own (EmpathyContactManager *manager,
225                                  McAccount             *account)
226 {
227         EmpathyContactManagerPriv *priv;
228         EmpathyContactList        *list;
229
230         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
231         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
232
233         priv = GET_PRIV (manager);
234
235         list = g_hash_table_lookup (priv->lists, account);
236         
237         if (!list) {
238                 return NULL;
239         }
240
241         return empathy_contact_list_get_own (list);
242 }
243
244 GossipContact *
245 empathy_contact_manager_create (EmpathyContactManager *manager,
246                                 McAccount             *account,
247                                 const gchar           *id)
248 {
249         EmpathyContactManagerPriv *priv;
250         EmpathyContactList        *list;
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         g_return_val_if_fail (id != NULL, NULL);
255
256         priv = GET_PRIV (manager);
257
258         list = g_hash_table_lookup (priv->lists, account);
259         
260         if (!list) {
261                 return NULL;
262         }
263
264         return empathy_contact_list_get_from_id (list, id);
265 }
266
267 GossipContact *
268 empathy_contact_manager_find (EmpathyContactManager *manager,
269                               const gchar           *id)
270 {
271         EmpathyContactManagerPriv *priv;
272         ContactManagerFindData     data;
273
274         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
275         g_return_val_if_fail (id != NULL, NULL);
276
277         priv = GET_PRIV (manager);
278
279         data.contact = NULL;
280         data.id = id;
281
282         g_hash_table_find (priv->lists,
283                            (GHRFunc) contact_manager_find_foreach,
284                            &data);
285
286         return data.contact;
287 }
288
289 void
290 empathy_contact_manager_add (EmpathyContactManager *manager,
291                              GossipContact         *contact,
292                              const gchar           *message)
293 {
294         EmpathyContactManagerPriv *priv;
295         EmpathyContactList        *list;
296         McAccount                 *account;
297         guint                      handle;
298
299         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
300         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
301
302         priv = GET_PRIV (manager);
303
304         account = gossip_contact_get_account (contact);
305         handle = gossip_contact_get_handle (contact);
306         list = g_hash_table_lookup (priv->lists, account);
307
308         if (list) {
309                 empathy_contact_list_add (list, handle, message);
310         }
311 }
312
313 void
314 empathy_contact_manager_remove (EmpathyContactManager *manager,
315                                 GossipContact         *contact)
316 {
317         EmpathyContactManagerPriv *priv;
318         EmpathyContactList        *list;
319         McAccount                 *account;
320         guint                      handle;
321
322         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
323         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
324
325         priv = GET_PRIV (manager);
326
327         account = gossip_contact_get_account (contact);
328         handle = gossip_contact_get_handle (contact);
329         list = g_hash_table_lookup (priv->lists, account);
330
331         if (list) {
332                 empathy_contact_list_remove (list, handle);
333         }
334 }
335
336 void
337 empathy_contact_manager_rename_group (EmpathyContactManager *manager,
338                                       const gchar           *old_group,
339                                       const gchar           *new_group)
340 {
341         EmpathyContactManagerPriv   *priv;
342         ContactManagerRenameGroupData  data;
343
344         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
345         g_return_if_fail (old_group != NULL);
346         g_return_if_fail (new_group != NULL);
347
348         priv = GET_PRIV (manager);
349
350         data.old_group = old_group;
351         data.new_group = new_group;
352
353         g_hash_table_foreach (priv->lists,
354                               (GHFunc) contact_manager_rename_group_foreach,
355                               &data);
356 }
357
358 GList *
359 empathy_contact_manager_get_groups (EmpathyContactManager *manager)
360 {
361         EmpathyContactManagerPriv *priv;
362         GList                     *groups = NULL;
363
364         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
365
366         priv = GET_PRIV (manager);
367
368         g_hash_table_foreach (priv->lists,
369                               (GHFunc) contact_manager_get_groups_foreach,
370                               &groups);
371
372         return groups;
373 }
374
375 GList *
376 empathy_contact_manager_get_contacts (EmpathyContactManager *manager)
377 {
378         EmpathyContactManagerPriv *priv;
379         GList                     *contacts = NULL;
380
381         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
382
383         priv = GET_PRIV (manager);
384
385         g_hash_table_foreach (priv->lists,
386                               (GHFunc) contact_manager_get_contacts_foreach,
387                               &contacts);
388
389         return contacts;
390 }
391
392 static void
393 contact_manager_setup_foreach (McAccount             *account,
394                                EmpathyContactList    *list,
395                                EmpathyContactManager *manager)
396 {
397         empathy_contact_list_setup (list);
398 }
399
400 static gboolean
401 contact_manager_find_foreach (McAccount              *account,
402                               EmpathyContactList     *list,
403                               ContactManagerFindData *data)
404 {
405         data->contact = empathy_contact_list_find (list, data->id);
406         
407         if (data->contact) {
408                 return TRUE;
409         }
410
411         return FALSE;
412 }
413
414 static void
415 contact_manager_add_account (EmpathyContactManager *manager,
416                              McAccount             *account)
417 {
418         EmpathyContactManagerPriv *priv;
419         EmpathyContactList        *list;
420
421         priv = GET_PRIV (manager);
422
423         if (g_hash_table_lookup (priv->lists, account)) {
424                 return;
425         }
426
427         gossip_debug (DEBUG_DOMAIN, "Adding new account: %s",
428                       mc_account_get_display_name (account));
429
430         list = empathy_contact_list_new (account);
431         if (!list) {
432                 return;
433         }
434
435         g_hash_table_insert (priv->lists, g_object_ref (account), list);
436
437         /* Connect signals */
438         g_signal_connect (list, "contact-added",
439                           G_CALLBACK (contact_manager_added_cb),
440                           manager);
441         g_signal_connect (list, "contact-removed",
442                           G_CALLBACK (contact_manager_removed_cb),
443                           manager);
444         g_signal_connect (list, "destroy",
445                           G_CALLBACK (contact_manager_destroy_cb),
446                           manager);
447
448         if (priv->setup) {
449                 empathy_contact_list_setup (list);
450         }
451 }
452
453 static void
454 contact_manager_added_cb (EmpathyContactList    *list,
455                           GossipContact         *contact,
456                           EmpathyContactManager *manager)
457 {
458         g_signal_emit (manager, signals[CONTACT_ADDED], 0, contact);
459 }
460
461 static void
462 contact_manager_removed_cb (EmpathyContactList    *list,
463                             GossipContact         *contact,
464                             EmpathyContactManager *manager)
465 {
466         g_signal_emit (manager, signals[CONTACT_REMOVED], 0, contact);
467 }
468
469 static void
470 contact_manager_destroy_cb (EmpathyContactList    *list,
471                             EmpathyContactManager *manager)
472 {
473         EmpathyContactManagerPriv *priv;
474         McAccount                 *account;
475
476         priv = GET_PRIV (manager);
477
478         account = empathy_contact_list_get_account (list);
479
480         gossip_debug (DEBUG_DOMAIN, "Removing account: %s",
481                       mc_account_get_display_name (account));
482
483         /* Disconnect signals from the list */
484         g_signal_handlers_disconnect_by_func (list,
485                                               contact_manager_added_cb,
486                                               manager);
487         g_signal_handlers_disconnect_by_func (list,
488                                               contact_manager_removed_cb,
489                                               manager);
490         g_signal_handlers_disconnect_by_func (list,
491                                               contact_manager_destroy_cb,
492                                               manager);
493
494         g_hash_table_remove (priv->lists, account);
495 }
496
497 static void
498 contact_manager_rename_group_foreach (McAccount                     *account,
499                                       EmpathyContactList            *list,
500                                       ContactManagerRenameGroupData *data)
501 {
502         empathy_contact_list_rename_group (list,
503                                            data->old_group,
504                                            data->new_group);
505 }
506
507 static void
508 contact_manager_get_groups_foreach (McAccount           *account,
509                                     EmpathyContactList  *list,
510                                     GList              **all_groups)
511 {
512         GList *groups, *l;
513
514         groups = empathy_contact_list_get_groups (list);
515         for (l = groups; l; l = l->next) {
516                 if (!g_list_find_custom (*all_groups,
517                                          l->data,
518                                          (GCompareFunc) strcmp)) {
519                         *all_groups = g_list_append (*all_groups,
520                                                      g_strdup (l->data));
521                 }
522                 g_free (l->data);
523         }
524
525         g_list_free (groups);
526 }
527
528 static void
529 contact_manager_get_contacts_foreach (McAccount           *account,
530                                       EmpathyContactList  *list,
531                                       GList              **contacts)
532 {
533         GList *l;
534
535         l = empathy_contact_list_get_contacts (list);
536         *contacts = g_list_concat (*contacts, l);
537 }
538
539 static void
540 contact_manager_status_changed_cb (MissionControl                  *mc,
541                                    TelepathyConnectionStatus        status,
542                                    McPresence                       presence,
543                                    TelepathyConnectionStatusReason  reason,
544                                    const gchar                     *unique_name,
545                                    EmpathyContactManager           *manager)
546 {
547         EmpathyContactManagerPriv *priv;
548         McAccount                 *account;
549
550         priv = GET_PRIV (manager);
551
552         if (status != TP_CONN_STATUS_CONNECTED) {
553                 /* We only care about newly connected accounts */
554                 return;
555         }
556
557         account = mc_account_lookup (unique_name);
558         contact_manager_add_account (manager, account);
559
560         g_object_unref (account);
561 }
562