]> git.0d.be Git - empathy.git/blob - libempathy/empathy-contact-manager.c
Add MSN setting UI. Fixes bug #443162 (Cosimo Cecchi).
[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 "empathy-contact-list.h"
31 #include "empathy-utils.h"
32 #include "empathy-debug.h"
33
34 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
35                        EMPATHY_TYPE_CONTACT_MANAGER, EmpathyContactManagerPriv))
36
37 #define DEBUG_DOMAIN "ContactManager"
38
39 struct _EmpathyContactManagerPriv {
40         GHashTable     *lists;
41         MissionControl *mc;
42         gboolean        setup;
43 };
44
45 typedef struct {
46         const gchar *old_group;
47         const gchar *new_group;
48 } ContactManagerRenameGroupData;
49
50 typedef struct {
51         EmpathyContact *contact;
52         const gchar   *id;
53 } ContactManagerFindData;
54
55 static void           empathy_contact_manager_class_init   (EmpathyContactManagerClass      *klass);
56 static void           contact_manager_iface_init           (EmpathyContactListIface         *iface);
57 static void           empathy_contact_manager_init         (EmpathyContactManager           *manager);
58 static void           contact_manager_finalize             (GObject                         *object);
59 static void           contact_manager_setup                (EmpathyContactList              *manager);
60 static EmpathyContact *contact_manager_find                 (EmpathyContactList              *manager,
61                                                             const gchar                     *id);
62 static void           contact_manager_add                  (EmpathyContactList              *manager,
63                                                             EmpathyContact                   *contact,
64                                                             const gchar                     *message);
65 static void           contact_manager_remove               (EmpathyContactList              *manager,
66                                                             EmpathyContact                   *contact,
67                                                             const gchar                     *message);
68 static GList *        contact_manager_get_members          (EmpathyContactList              *manager);
69 static GList *        contact_manager_get_local_pending    (EmpathyContactList              *manager);
70 static void           contact_manager_process_pending      (EmpathyContactList              *manager,
71                                                             EmpathyContact                   *contact,
72                                                             gboolean                         accept);
73 static void           contact_manager_setup_foreach        (McAccount                       *account,
74                                                             EmpathyTpContactList            *list,
75                                                             EmpathyContactManager           *manager);
76 static gboolean       contact_manager_find_foreach         (McAccount                       *account,
77                                                             EmpathyTpContactList            *list,
78                                                             ContactManagerFindData          *data);
79 static void           contact_manager_add_account          (EmpathyContactManager           *manager,
80                                                             McAccount                       *account);
81 static void           contact_manager_added_cb             (EmpathyTpContactList            *list,
82                                                             EmpathyContact                   *contact,
83                                                             EmpathyContactManager           *manager);
84 static void           contact_manager_removed_cb           (EmpathyTpContactList            *list,
85                                                             EmpathyContact                   *contact,
86                                                             EmpathyContactManager           *manager);
87 static void           contact_manager_local_pending_cb     (EmpathyTpContactList            *list,
88                                                             EmpathyContact                   *contact,
89                                                             const gchar                     *message,
90                                                             EmpathyContactManager           *manager);
91 static void           contact_manager_destroy_cb           (EmpathyTpContactList            *list,
92                                                             EmpathyContactManager           *manager);
93 static void           contact_manager_rename_group_foreach (McAccount                       *account,
94                                                             EmpathyTpContactList            *list,
95                                                             ContactManagerRenameGroupData   *data);
96 static void           contact_manager_get_groups_foreach   (McAccount                       *account,
97                                                             EmpathyTpContactList            *list,
98                                                             GList                          **all_groups);
99 static void           contact_manager_get_members_foreach  (McAccount                       *account,
100                                                             EmpathyTpContactList            *list,
101                                                             GList                          **contacts);
102 static void           contact_manager_get_local_pending_foreach (McAccount                  *account,
103                                                             EmpathyTpContactList            *list,
104                                                             GList                          **contacts);
105 static void           contact_manager_status_changed_cb    (MissionControl                  *mc,
106                                                             TelepathyConnectionStatus        status,
107                                                             McPresence                       presence,
108                                                             TelepathyConnectionStatusReason  reason,
109                                                             const gchar                     *unique_name,
110                                                             EmpathyContactManager           *manager);
111
112 G_DEFINE_TYPE_WITH_CODE (EmpathyContactManager, empathy_contact_manager, G_TYPE_OBJECT,
113                          G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_CONTACT_LIST,
114                                                 contact_manager_iface_init));
115
116 static void
117 empathy_contact_manager_class_init (EmpathyContactManagerClass *klass)
118 {
119         GObjectClass *object_class = G_OBJECT_CLASS (klass);
120
121         object_class->finalize = contact_manager_finalize;
122
123         g_type_class_add_private (object_class, sizeof (EmpathyContactManagerPriv));
124 }
125
126 static void
127 contact_manager_iface_init (EmpathyContactListIface *iface)
128 {
129         iface->setup             = contact_manager_setup;
130         iface->find              = contact_manager_find;
131         iface->add               = contact_manager_add;
132         iface->remove            = contact_manager_remove;
133         iface->get_members       = contact_manager_get_members;
134         iface->get_local_pending = contact_manager_get_local_pending;
135         iface->process_pending   = contact_manager_process_pending;
136 }
137
138 static void
139 empathy_contact_manager_init (EmpathyContactManager *manager)
140 {
141         EmpathyContactManagerPriv *priv;
142         GSList                    *accounts, *l;
143
144         priv = GET_PRIV (manager);
145
146         priv->lists = g_hash_table_new_full (empathy_account_hash,
147                                              empathy_account_equal,
148                                              (GDestroyNotify) g_object_unref,
149                                              (GDestroyNotify) g_object_unref);
150
151         priv->mc = empathy_mission_control_new ();
152
153         dbus_g_proxy_connect_signal (DBUS_G_PROXY (priv->mc),
154                                      "AccountStatusChanged",
155                                      G_CALLBACK (contact_manager_status_changed_cb),
156                                      manager, NULL);
157
158         /* Get ContactList for existing connections */
159         accounts = mission_control_get_online_connections (priv->mc, NULL);
160         for (l = accounts; l; l = l->next) {
161                 McAccount *account;
162
163                 account = l->data;
164                 contact_manager_add_account (manager, account);
165                 
166                 g_object_unref (account);
167         }
168         g_slist_free (accounts);
169 }
170
171 static void
172 contact_manager_finalize (GObject *object)
173 {
174         EmpathyContactManagerPriv *priv;
175
176         priv = GET_PRIV (object);
177
178         g_hash_table_destroy (priv->lists);
179         g_object_unref (priv->mc);
180 }
181
182 EmpathyContactManager *
183 empathy_contact_manager_new (void)
184 {
185         static EmpathyContactManager *manager = NULL;
186
187         if (!manager) {
188                 manager = g_object_new (EMPATHY_TYPE_CONTACT_MANAGER, NULL);
189                 g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
190         } else {
191                 g_object_ref (manager);
192         }
193
194         return manager;
195 }
196
197 static void
198 contact_manager_setup (EmpathyContactList *manager)
199 {
200         EmpathyContactManagerPriv *priv;
201
202         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
203
204         priv = GET_PRIV (manager);
205
206         if (priv->setup) {
207                 /* Already done */
208                 return;
209         }
210
211         g_hash_table_foreach (priv->lists,
212                               (GHFunc) contact_manager_setup_foreach,
213                               manager);
214
215         priv->setup = TRUE;
216 }
217
218 static EmpathyContact *
219 contact_manager_find (EmpathyContactList *manager,
220                       const gchar        *id)
221 {
222         EmpathyContactManagerPriv *priv;
223         ContactManagerFindData     data;
224
225         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
226         g_return_val_if_fail (id != NULL, NULL);
227
228         priv = GET_PRIV (manager);
229
230         data.contact = NULL;
231         data.id = id;
232
233         g_hash_table_find (priv->lists,
234                            (GHRFunc) contact_manager_find_foreach,
235                            &data);
236
237         return data.contact;
238 }
239
240 static void
241 contact_manager_add (EmpathyContactList *manager,
242                      EmpathyContact      *contact,
243                      const gchar        *message)
244 {
245         EmpathyContactManagerPriv *priv;
246         EmpathyContactList        *list;
247         McAccount                 *account;
248
249         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
250         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
251
252         priv = GET_PRIV (manager);
253
254         account = empathy_contact_get_account (contact);
255         list = g_hash_table_lookup (priv->lists, account);
256
257         if (list) {
258                 empathy_contact_list_add (list, contact, message);
259         }
260 }
261
262 static void
263 contact_manager_remove (EmpathyContactList *manager,
264                         EmpathyContact      *contact,
265                         const gchar        *message)
266 {
267         EmpathyContactManagerPriv *priv;
268         EmpathyContactList        *list;
269         McAccount                 *account;
270
271         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
272         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
273
274         priv = GET_PRIV (manager);
275
276         account = empathy_contact_get_account (contact);
277         list = g_hash_table_lookup (priv->lists, account);
278
279         if (list) {
280                 empathy_contact_list_remove (list, contact, message);
281         }
282 }
283
284 static GList *
285 contact_manager_get_members (EmpathyContactList *manager)
286 {
287         EmpathyContactManagerPriv *priv;
288         GList                     *contacts = NULL;
289
290         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
291
292         priv = GET_PRIV (manager);
293
294         g_hash_table_foreach (priv->lists,
295                               (GHFunc) contact_manager_get_members_foreach,
296                               &contacts);
297
298         return contacts;
299 }
300
301 static GList *
302 contact_manager_get_local_pending (EmpathyContactList *manager)
303 {
304         EmpathyContactManagerPriv *priv;
305         GList                     *pending = NULL;
306
307         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
308
309         priv = GET_PRIV (manager);
310
311         g_hash_table_foreach (priv->lists,
312                               (GHFunc) contact_manager_get_local_pending_foreach,
313                               &pending);
314
315         return pending;
316 }
317
318 static void
319 contact_manager_process_pending (EmpathyContactList *manager,
320                                  EmpathyContact      *contact,
321                                  gboolean            accept)
322 {
323         EmpathyContactManagerPriv *priv;
324         EmpathyContactList        *list;
325         McAccount                 *account;
326
327         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
328         g_return_if_fail (EMPATHY_IS_CONTACT (contact));
329
330         priv = GET_PRIV (manager);
331
332         account = empathy_contact_get_account (contact);
333         list = g_hash_table_lookup (priv->lists, account);
334
335         if (list) {
336                 empathy_contact_list_process_pending (list, contact, accept);
337         }
338 }
339
340 EmpathyTpContactList *
341 empathy_contact_manager_get_list (EmpathyContactManager *manager,
342                                   McAccount             *account)
343 {
344         EmpathyContactManagerPriv *priv;
345
346         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
347         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
348
349         priv = GET_PRIV (manager);
350
351         return g_hash_table_lookup (priv->lists, account);
352 }
353
354 EmpathyContact *
355 empathy_contact_manager_get_user (EmpathyContactManager *manager,
356                                   McAccount             *account)
357 {
358         EmpathyContactManagerPriv *priv;
359         EmpathyTpContactList        *list;
360
361         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
362         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
363
364         priv = GET_PRIV (manager);
365
366         list = g_hash_table_lookup (priv->lists, account);
367         
368         if (!list) {
369                 return NULL;
370         }
371
372         return empathy_tp_contact_list_get_user (list);
373 }
374
375 EmpathyContact *
376 empathy_contact_manager_create (EmpathyContactManager *manager,
377                                 McAccount             *account,
378                                 const gchar           *id)
379 {
380         EmpathyContactManagerPriv *priv;
381         EmpathyTpContactList      *list;
382
383         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
384         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
385         g_return_val_if_fail (id != NULL, NULL);
386
387         priv = GET_PRIV (manager);
388
389         list = g_hash_table_lookup (priv->lists, account);
390         
391         if (!list) {
392                 return NULL;
393         }
394
395         return empathy_tp_contact_list_get_from_id (list, id);
396 }
397
398 void
399 empathy_contact_manager_rename_group (EmpathyContactManager *manager,
400                                       const gchar           *old_group,
401                                       const gchar           *new_group)
402 {
403         EmpathyContactManagerPriv   *priv;
404         ContactManagerRenameGroupData  data;
405
406         g_return_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager));
407         g_return_if_fail (old_group != NULL);
408         g_return_if_fail (new_group != NULL);
409
410         priv = GET_PRIV (manager);
411
412         data.old_group = old_group;
413         data.new_group = new_group;
414
415         g_hash_table_foreach (priv->lists,
416                               (GHFunc) contact_manager_rename_group_foreach,
417                               &data);
418 }
419
420 GList *
421 empathy_contact_manager_get_groups (EmpathyContactManager *manager)
422 {
423         EmpathyContactManagerPriv *priv;
424         GList                     *groups = NULL;
425
426         g_return_val_if_fail (EMPATHY_IS_CONTACT_MANAGER (manager), NULL);
427
428         priv = GET_PRIV (manager);
429
430         g_hash_table_foreach (priv->lists,
431                               (GHFunc) contact_manager_get_groups_foreach,
432                               &groups);
433
434         return groups;
435 }
436
437 static void
438 contact_manager_setup_foreach (McAccount             *account,
439                                EmpathyTpContactList  *list,
440                                EmpathyContactManager *manager)
441 {
442         empathy_contact_list_setup (EMPATHY_CONTACT_LIST (list));
443 }
444
445 static gboolean
446 contact_manager_find_foreach (McAccount              *account,
447                               EmpathyTpContactList   *list,
448                               ContactManagerFindData *data)
449 {
450         data->contact = empathy_contact_list_find (EMPATHY_CONTACT_LIST (list),
451                                                    data->id);
452
453         if (data->contact) {
454                 return TRUE;
455         }
456
457         return FALSE;
458 }
459
460 static void
461 contact_manager_add_account (EmpathyContactManager *manager,
462                              McAccount             *account)
463 {
464         EmpathyContactManagerPriv *priv;
465         EmpathyTpContactList        *list;
466
467         priv = GET_PRIV (manager);
468
469         if (g_hash_table_lookup (priv->lists, account)) {
470                 return;
471         }
472
473         empathy_debug (DEBUG_DOMAIN, "Adding new account: %s",
474                       mc_account_get_display_name (account));
475
476         list = empathy_tp_contact_list_new (account);
477         if (!list) {
478                 return;
479         }
480
481         g_hash_table_insert (priv->lists, g_object_ref (account), list);
482
483         /* Connect signals */
484         g_signal_connect (list, "contact-added",
485                           G_CALLBACK (contact_manager_added_cb),
486                           manager);
487         g_signal_connect (list, "contact-removed",
488                           G_CALLBACK (contact_manager_removed_cb),
489                           manager);
490         g_signal_connect (list, "local-pending",
491                           G_CALLBACK (contact_manager_local_pending_cb),
492                           manager);
493         g_signal_connect (list, "destroy",
494                           G_CALLBACK (contact_manager_destroy_cb),
495                           manager);
496
497         if (priv->setup) {
498                 empathy_contact_list_setup (EMPATHY_CONTACT_LIST (list));
499         }
500 }
501
502 static void
503 contact_manager_added_cb (EmpathyTpContactList  *list,
504                           EmpathyContact         *contact,
505                           EmpathyContactManager *manager)
506 {
507         g_signal_emit_by_name (manager, "contact-added", contact);
508 }
509
510 static void
511 contact_manager_removed_cb (EmpathyTpContactList  *list,
512                             EmpathyContact         *contact,
513                             EmpathyContactManager *manager)
514 {
515         g_signal_emit_by_name (manager, "contact-removed", contact);
516 }
517
518 static void
519 contact_manager_local_pending_cb (EmpathyTpContactList  *list,
520                                   EmpathyContact         *contact,
521                                   const gchar           *message,
522                                   EmpathyContactManager *manager)
523 {
524         g_signal_emit_by_name (manager, "local-pending", contact, message);
525 }
526
527 static void
528 contact_manager_destroy_cb (EmpathyTpContactList  *list,
529                             EmpathyContactManager *manager)
530 {
531         EmpathyContactManagerPriv *priv;
532         McAccount                 *account;
533
534         priv = GET_PRIV (manager);
535
536         account = empathy_tp_contact_list_get_account (list);
537
538         empathy_debug (DEBUG_DOMAIN, "Removing account: %s",
539                       mc_account_get_display_name (account));
540
541         /* Disconnect signals from the list */
542         g_signal_handlers_disconnect_by_func (list,
543                                               contact_manager_added_cb,
544                                               manager);
545         g_signal_handlers_disconnect_by_func (list,
546                                               contact_manager_removed_cb,
547                                               manager);
548         g_signal_handlers_disconnect_by_func (list,
549                                               contact_manager_local_pending_cb,
550                                               manager);
551         g_signal_handlers_disconnect_by_func (list,
552                                               contact_manager_destroy_cb,
553                                               manager);
554
555         g_hash_table_remove (priv->lists, account);
556 }
557
558 static void
559 contact_manager_rename_group_foreach (McAccount                     *account,
560                                       EmpathyTpContactList          *list,
561                                       ContactManagerRenameGroupData *data)
562 {
563         empathy_tp_contact_list_rename_group (list,
564                                               data->old_group,
565                                               data->new_group);
566 }
567
568 static void
569 contact_manager_get_groups_foreach (McAccount             *account,
570                                     EmpathyTpContactList  *list,
571                                     GList                **all_groups)
572 {
573         GList *groups, *l;
574
575         groups = empathy_tp_contact_list_get_groups (list);
576         for (l = groups; l; l = l->next) {
577                 if (!g_list_find_custom (*all_groups,
578                                          l->data,
579                                          (GCompareFunc) strcmp)) {
580                         *all_groups = g_list_append (*all_groups,
581                                                      g_strdup (l->data));
582                 }
583                 g_free (l->data);
584         }
585
586         g_list_free (groups);
587 }
588
589 static void
590 contact_manager_get_members_foreach (McAccount             *account,
591                                      EmpathyTpContactList  *list,
592                                      GList                **contacts)
593 {
594         GList *l;
595
596         l = empathy_contact_list_get_members (EMPATHY_CONTACT_LIST (list));
597         *contacts = g_list_concat (*contacts, l);
598 }
599
600 static void
601 contact_manager_get_local_pending_foreach (McAccount             *account,
602                                            EmpathyTpContactList  *list,
603                                            GList                **contacts)
604 {
605         GList *l;
606
607         l = empathy_contact_list_get_local_pending (EMPATHY_CONTACT_LIST (list));
608         *contacts = g_list_concat (*contacts, l);
609 }
610
611 static void
612 contact_manager_status_changed_cb (MissionControl                  *mc,
613                                    TelepathyConnectionStatus        status,
614                                    McPresence                       presence,
615                                    TelepathyConnectionStatusReason  reason,
616                                    const gchar                     *unique_name,
617                                    EmpathyContactManager           *manager)
618 {
619         EmpathyContactManagerPriv *priv;
620         McAccount                 *account;
621
622         priv = GET_PRIV (manager);
623
624         if (status != TP_CONN_STATUS_CONNECTED) {
625                 /* We only care about newly connected accounts */
626                 return;
627         }
628
629         account = mc_account_lookup (unique_name);
630         contact_manager_add_account (manager, account);
631
632         g_object_unref (account);
633 }
634