]> git.0d.be Git - empathy.git/blob - libempathy/empathy-chatroom-manager.c
tp-contact-factory: request avatar feature
[empathy.git] / libempathy / empathy-chatroom-manager.c
1 /*
2  * Copyright (C) 2004-2007 Imendio AB
3  * Copyright (C) 2007-2009 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., 51 Franklin St, Fifth Floor,
18  * Boston, MA  02110-1301  USA
19  *
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  *          Martyn Russell <martyn@imendio.com>
22  */
23
24 #include "config.h"
25
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
32
33 #include <telepathy-glib/account-manager.h>
34 #include <telepathy-glib/interfaces.h>
35 #include <telepathy-glib/util.h>
36
37 #include "empathy-tp-chat.h"
38 #include "empathy-chatroom-manager.h"
39 #include "empathy-utils.h"
40
41 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
42 #include "empathy-debug.h"
43
44 #define CHATROOMS_XML_FILENAME "chatrooms.xml"
45 #define CHATROOMS_DTD_FILENAME "empathy-chatroom-manager.dtd"
46 #define SAVE_TIMER 4
47
48 static EmpathyChatroomManager *chatroom_manager_singleton = NULL;
49
50 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChatroomManager)
51 typedef struct
52 {
53   GList *chatrooms;
54   gchar *file;
55   TpAccountManager *account_manager;
56
57   /* source id of the autosave timer */
58   gint save_timer_id;
59   gboolean ready;
60 } EmpathyChatroomManagerPriv;
61
62 enum {
63   CHATROOM_ADDED,
64   CHATROOM_REMOVED,
65   LAST_SIGNAL
66 };
67
68 static guint signals[LAST_SIGNAL];
69
70 /* properties */
71 enum
72 {
73   PROP_FILE = 1,
74   PROP_READY,
75   LAST_PROPERTY
76 };
77
78 G_DEFINE_TYPE (EmpathyChatroomManager, empathy_chatroom_manager, G_TYPE_OBJECT);
79
80 /*
81  * API to save/load and parse the chatrooms file.
82  */
83
84 static gboolean
85 chatroom_manager_file_save (EmpathyChatroomManager *manager)
86 {
87         EmpathyChatroomManagerPriv *priv;
88         xmlDocPtr                  doc;
89         xmlNodePtr                 root;
90         GList                     *l;
91
92         priv = GET_PRIV (manager);
93
94         doc = xmlNewDoc ((const xmlChar *) "1.0");
95         root = xmlNewNode (NULL, (const xmlChar *) "chatrooms");
96         xmlDocSetRootElement (doc, root);
97
98         for (l = priv->chatrooms; l; l = l->next) {
99                 EmpathyChatroom *chatroom;
100                 xmlNodePtr       node;
101                 const gchar     *account_id;
102
103                 chatroom = l->data;
104
105                 if (!empathy_chatroom_is_favorite (chatroom)) {
106                         continue;
107                 }
108
109                 account_id = tp_proxy_get_object_path (
110                   empathy_chatroom_get_account (chatroom));
111
112                 node = xmlNewChild (root, NULL, (const xmlChar *) "chatroom", NULL);
113                 xmlNewTextChild (node, NULL, (const xmlChar *) "name",
114                         (const xmlChar *) empathy_chatroom_get_name (chatroom));
115                 xmlNewTextChild (node, NULL, (const xmlChar *) "room",
116                         (const xmlChar *) empathy_chatroom_get_room (chatroom));
117                 xmlNewTextChild (node, NULL, (const xmlChar *) "account",
118                         (const xmlChar *) account_id);
119                 xmlNewTextChild (node, NULL, (const xmlChar *) "auto_connect",
120                         empathy_chatroom_get_auto_connect (chatroom) ?
121                         (const xmlChar *) "yes" : (const xmlChar *) "no");
122                 xmlNewTextChild (node, NULL, (const xmlChar *) "always_urgent",
123                         empathy_chatroom_is_always_urgent (chatroom) ?
124                         (const xmlChar *) "yes" : (const xmlChar *) "no");
125         }
126
127         /* Make sure the XML is indented properly */
128         xmlIndentTreeOutput = 1;
129
130         DEBUG ("Saving file:'%s'", priv->file);
131         xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1);
132         xmlFreeDoc (doc);
133
134         xmlMemoryDump ();
135
136         return TRUE;
137 }
138
139 static gboolean
140 save_timeout (EmpathyChatroomManager *self)
141 {
142   EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
143
144   priv->save_timer_id = 0;
145   chatroom_manager_file_save (self);
146
147   return FALSE;
148 }
149
150 static void
151 reset_save_timeout (EmpathyChatroomManager *self)
152 {
153   EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
154
155   if (priv->save_timer_id > 0)
156     {
157       g_source_remove (priv->save_timer_id);
158     }
159
160   priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER,
161       (GSourceFunc) save_timeout, self);
162 }
163
164 static void
165 chatroom_changed_cb (EmpathyChatroom *chatroom,
166                      GParamSpec *spec,
167                      EmpathyChatroomManager *self)
168 {
169   reset_save_timeout (self);
170 }
171
172 static void
173 add_chatroom (EmpathyChatroomManager *self,
174               EmpathyChatroom *chatroom)
175 {
176   EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
177
178   priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom));
179
180   g_signal_connect (chatroom, "notify",
181       G_CALLBACK (chatroom_changed_cb), self);
182 }
183
184 static void
185 chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager,
186                                  xmlNodePtr             node)
187 {
188         EmpathyChatroomManagerPriv *priv;
189         EmpathyChatroom            *chatroom;
190         TpAccount                  *account;
191         xmlNodePtr                 child;
192         gchar                     *str;
193         gchar                     *name;
194         gchar                     *room;
195         gchar                     *account_id;
196         gboolean                   auto_connect;
197         gboolean                   always_urgent;
198
199         priv = GET_PRIV (manager);
200
201         /* default values. */
202         name = NULL;
203         room = NULL;
204         auto_connect = TRUE;
205         always_urgent = FALSE;
206         account_id = NULL;
207
208         for (child = node->children; child; child = child->next) {
209                 gchar *tag;
210
211                 if (xmlNodeIsText (child)) {
212                         continue;
213                 }
214
215                 tag = (gchar *) child->name;
216                 str = (gchar *) xmlNodeGetContent (child);
217
218                 if (strcmp (tag, "name") == 0) {
219                         name = g_strdup (str);
220                 }
221                 else if (strcmp (tag, "room") == 0) {
222                         room = g_strdup (str);
223                 }
224                 else if (strcmp (tag, "auto_connect") == 0) {
225                         if (strcmp (str, "yes") == 0) {
226                                 auto_connect = TRUE;
227                         } else {
228                                 auto_connect = FALSE;
229                         }
230                 }
231                 else if (!tp_strdiff (tag, "always_urgent")) {
232                         if (strcmp (str, "yes") == 0) {
233                                 always_urgent = TRUE;
234                         } else {
235                                 always_urgent = FALSE;
236                         }
237                 }
238                 else if (strcmp (tag, "account") == 0) {
239                         account_id = g_strdup (str);
240                 }
241
242                 xmlFree (str);
243         }
244
245         account = tp_account_manager_ensure_account (priv->account_manager,
246                 account_id);
247         if (!account) {
248                 g_free (name);
249                 g_free (room);
250                 g_free (account_id);
251                 return;
252         }
253
254         chatroom = empathy_chatroom_new_full (account, room, name, auto_connect);
255         empathy_chatroom_set_favorite (chatroom, TRUE);
256         empathy_chatroom_set_always_urgent (chatroom, always_urgent);
257         add_chatroom (manager, chatroom);
258         g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom);
259
260         g_free (name);
261         g_free (room);
262         g_free (account_id);
263 }
264
265 static gboolean
266 chatroom_manager_file_parse (EmpathyChatroomManager *manager,
267                              const gchar           *filename)
268 {
269         EmpathyChatroomManagerPriv *priv;
270         xmlParserCtxtPtr           ctxt;
271         xmlDocPtr                  doc;
272         xmlNodePtr                 chatrooms;
273         xmlNodePtr                 node;
274
275         priv = GET_PRIV (manager);
276
277         DEBUG ("Attempting to parse file:'%s'...", filename);
278
279         ctxt = xmlNewParserCtxt ();
280
281         /* Parse and validate the file. */
282         doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
283         if (!doc) {
284                 g_warning ("Failed to parse file:'%s'", filename);
285                 xmlFreeParserCtxt (ctxt);
286                 return FALSE;
287         }
288
289         if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME)) {
290                 g_warning ("Failed to validate file:'%s'", filename);
291                 xmlFreeDoc (doc);
292                 xmlFreeParserCtxt (ctxt);
293                 return FALSE;
294         }
295
296         /* The root node, chatrooms. */
297         chatrooms = xmlDocGetRootElement (doc);
298
299         for (node = chatrooms->children; node; node = node->next) {
300                 if (strcmp ((gchar *) node->name, "chatroom") == 0) {
301                         chatroom_manager_parse_chatroom (manager, node);
302                 }
303         }
304
305         DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms));
306
307         xmlFreeDoc (doc);
308         xmlFreeParserCtxt (ctxt);
309
310         return TRUE;
311 }
312
313 static gboolean
314 chatroom_manager_get_all (EmpathyChatroomManager *manager)
315 {
316         EmpathyChatroomManagerPriv *priv;
317
318         priv = GET_PRIV (manager);
319
320         /* read file in */
321         if (g_file_test (priv->file, G_FILE_TEST_EXISTS) &&
322             !chatroom_manager_file_parse (manager, priv->file)) {
323                 return FALSE;
324         }
325
326         priv->ready = TRUE;
327         g_object_notify (G_OBJECT (manager), "ready");
328
329         return TRUE;
330 }
331
332 static void
333 empathy_chatroom_manager_get_property (GObject *object,
334                                        guint property_id,
335                                        GValue *value,
336                                        GParamSpec *pspec)
337 {
338   EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object);
339   EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
340
341   switch (property_id)
342     {
343       case PROP_FILE:
344         g_value_set_string (value, priv->file);
345         break;
346       case PROP_READY:
347         g_value_set_boolean (value, priv->ready);
348         break;
349       default:
350         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
351         break;
352     }
353 }
354
355 static void
356 empathy_chatroom_manager_set_property (GObject *object,
357                                        guint property_id,
358                                        const GValue *value,
359                                        GParamSpec *pspec)
360 {
361   EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object);
362   EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
363
364   switch (property_id)
365     {
366       case PROP_FILE:
367         g_free (priv->file);
368         priv->file = g_value_dup_string (value);
369         break;
370       default:
371         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
372         break;
373     }
374 }
375
376 static void
377 chatroom_manager_finalize (GObject *object)
378 {
379   EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object);
380   EmpathyChatroomManagerPriv *priv;
381   GList *l;
382
383   priv = GET_PRIV (object);
384
385   g_object_unref (priv->account_manager);
386
387   if (priv->save_timer_id > 0)
388     {
389       /* have to save before destroy the object */
390       g_source_remove (priv->save_timer_id);
391       priv->save_timer_id = 0;
392       chatroom_manager_file_save (self);
393     }
394
395   for (l = priv->chatrooms; l != NULL; l = g_list_next (l))
396     {
397       EmpathyChatroom *chatroom = l->data;
398
399       g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb,
400           self);
401
402       g_object_unref (chatroom);
403     }
404
405   g_list_free (priv->chatrooms);
406   g_free (priv->file);
407
408   (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object);
409 }
410
411 static void
412 account_manager_ready_cb (GObject *source_object,
413                           GAsyncResult *result,
414                           gpointer user_data)
415 {
416   EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (user_data);
417   TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
418   GError *error = NULL;
419
420   if (!tp_account_manager_prepare_finish (manager, result, &error))
421     {
422       DEBUG ("Failed to prepare account manager: %s", error->message);
423       g_error_free (error);
424       goto out;
425     }
426
427   chatroom_manager_get_all (self);
428
429 out:
430   g_object_unref (self);
431 }
432
433 static GObject *
434 empathy_chatroom_manager_constructor (GType type,
435                                       guint n_props,
436                                       GObjectConstructParam *props)
437 {
438   GObject *obj;
439   EmpathyChatroomManager *self;
440   EmpathyChatroomManagerPriv *priv;
441
442   if (chatroom_manager_singleton != NULL)
443     return g_object_ref (chatroom_manager_singleton);
444
445   /* Parent constructor chain */
446   obj = G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->
447         constructor (type, n_props, props);
448
449   self = EMPATHY_CHATROOM_MANAGER (obj);
450   priv = GET_PRIV (self);
451
452   priv->ready = FALSE;
453
454   chatroom_manager_singleton = self;
455   g_object_add_weak_pointer (obj, (gpointer) &chatroom_manager_singleton);
456
457   priv->account_manager = tp_account_manager_dup ();
458
459   tp_account_manager_prepare_async (priv->account_manager, NULL,
460       account_manager_ready_cb, g_object_ref (self));
461
462   if (priv->file == NULL)
463     {
464       /* Set the default file path */
465       gchar *dir;
466
467       dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
468       if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
469         g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
470
471       priv->file = g_build_filename (dir, CHATROOMS_XML_FILENAME, NULL);
472       g_free (dir);
473     }
474
475   return obj;
476 }
477
478 static void
479 empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass)
480 {
481   GObjectClass *object_class = G_OBJECT_CLASS (klass);
482   GParamSpec *param_spec;
483
484   object_class->constructor = empathy_chatroom_manager_constructor;
485   object_class->get_property = empathy_chatroom_manager_get_property;
486   object_class->set_property = empathy_chatroom_manager_set_property;
487         object_class->finalize = chatroom_manager_finalize;
488
489   param_spec = g_param_spec_string (
490       "file",
491       "path of the favorite file",
492       "The path of the XML file containing user's favorites",
493       NULL,
494       G_PARAM_CONSTRUCT_ONLY |
495       G_PARAM_READWRITE |
496       G_PARAM_STATIC_NAME |
497       G_PARAM_STATIC_NICK |
498       G_PARAM_STATIC_BLURB);
499   g_object_class_install_property (object_class, PROP_FILE, param_spec);
500
501   param_spec = g_param_spec_boolean (
502       "ready",
503       "whether the manager is ready yet",
504       "whether the manager is ready yet",
505       FALSE,
506       G_PARAM_READABLE);
507   g_object_class_install_property (object_class, PROP_READY, param_spec);
508
509   signals[CHATROOM_ADDED] = g_signal_new ("chatroom-added",
510       G_TYPE_FROM_CLASS (klass),
511       G_SIGNAL_RUN_LAST,
512       0, NULL, NULL,
513       g_cclosure_marshal_VOID__OBJECT,
514       G_TYPE_NONE,
515       1, EMPATHY_TYPE_CHATROOM);
516
517   signals[CHATROOM_REMOVED] = g_signal_new ("chatroom-removed",
518       G_TYPE_FROM_CLASS (klass),
519       G_SIGNAL_RUN_LAST,
520       0, NULL, NULL,
521       g_cclosure_marshal_VOID__OBJECT,
522       G_TYPE_NONE,
523       1, EMPATHY_TYPE_CHATROOM);
524
525   g_type_class_add_private (object_class, sizeof (EmpathyChatroomManagerPriv));
526 }
527
528 static void
529 empathy_chatroom_manager_init (EmpathyChatroomManager *manager)
530 {
531   EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
532       EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv);
533
534   manager->priv = priv;
535 }
536
537 EmpathyChatroomManager *
538 empathy_chatroom_manager_dup_singleton (const gchar *file)
539 {
540   return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER,
541       "file", file, NULL));
542 }
543
544 gboolean
545 empathy_chatroom_manager_add (EmpathyChatroomManager *manager,
546                              EmpathyChatroom        *chatroom)
547 {
548   EmpathyChatroomManagerPriv *priv;
549
550   g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE);
551   g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE);
552
553   priv = GET_PRIV (manager);
554
555   /* don't add more than once */
556   if (!empathy_chatroom_manager_find (manager,
557       empathy_chatroom_get_account (chatroom),
558       empathy_chatroom_get_room (chatroom)))
559     {
560       add_chatroom (manager, chatroom);
561
562       if (empathy_chatroom_is_favorite (chatroom))
563         reset_save_timeout (manager);
564
565       g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom);
566       return TRUE;
567     }
568
569   return FALSE;
570 }
571
572 static void
573 chatroom_manager_remove_link (EmpathyChatroomManager *manager,
574                               GList *l)
575 {
576   EmpathyChatroomManagerPriv *priv;
577   EmpathyChatroom *chatroom;
578
579   priv = GET_PRIV (manager);
580
581   chatroom = l->data;
582
583   if (empathy_chatroom_is_favorite (chatroom))
584     reset_save_timeout (manager);
585
586   priv->chatrooms = g_list_delete_link (priv->chatrooms, l);
587
588   g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, chatroom);
589   g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, manager);
590
591   g_object_unref (chatroom);
592 }
593
594 void
595 empathy_chatroom_manager_remove (EmpathyChatroomManager *manager,
596                                  EmpathyChatroom        *chatroom)
597 {
598   EmpathyChatroomManagerPriv *priv;
599   GList *l;
600
601   g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager));
602   g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom));
603
604   priv = GET_PRIV (manager);
605
606   for (l = priv->chatrooms; l; l = l->next)
607     {
608       EmpathyChatroom *this_chatroom;
609
610       this_chatroom = l->data;
611
612       if (this_chatroom == chatroom ||
613           empathy_chatroom_equal (chatroom, this_chatroom))
614         {
615           chatroom_manager_remove_link (manager, l);
616           break;
617         }
618     }
619 }
620
621 EmpathyChatroom *
622 empathy_chatroom_manager_find (EmpathyChatroomManager *manager,
623                                TpAccount *account,
624                                const gchar *room)
625 {
626         EmpathyChatroomManagerPriv *priv;
627         GList                     *l;
628
629         g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), NULL);
630         g_return_val_if_fail (room != NULL, NULL);
631
632         priv = GET_PRIV (manager);
633
634         for (l = priv->chatrooms; l; l = l->next) {
635                 EmpathyChatroom *chatroom;
636                 TpAccount *this_account;
637                 const gchar    *this_room;
638
639                 chatroom = l->data;
640                 this_account = empathy_chatroom_get_account (chatroom);
641                 this_room = empathy_chatroom_get_room (chatroom);
642
643                 if (this_account && this_room && account == this_account
644                                 && strcmp (this_room, room) == 0) {
645                         return chatroom;
646                 }
647         }
648
649         return NULL;
650 }
651
652 EmpathyChatroom *
653 empathy_chatroom_manager_ensure_chatroom (EmpathyChatroomManager *manager,
654                                           TpAccount *account,
655                                           const gchar *room,
656                                           const gchar *name)
657 {
658         EmpathyChatroom *chatroom;
659
660         chatroom = empathy_chatroom_manager_find (manager, account, room);
661
662         if (chatroom) {
663                 return g_object_ref (chatroom);
664         } else {
665                 chatroom = empathy_chatroom_new_full (account,
666                         room,
667                         name,
668                         FALSE);
669                 empathy_chatroom_manager_add (manager, chatroom);
670                 return chatroom;
671         }
672 }
673
674 GList *
675 empathy_chatroom_manager_get_chatrooms (EmpathyChatroomManager *manager,
676                                        TpAccount *account)
677 {
678         EmpathyChatroomManagerPriv *priv;
679         GList                     *chatrooms, *l;
680
681         g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), NULL);
682
683         priv = GET_PRIV (manager);
684
685         if (!account) {
686                 return g_list_copy (priv->chatrooms);
687         }
688
689         chatrooms = NULL;
690         for (l = priv->chatrooms; l; l = l->next) {
691                 EmpathyChatroom *chatroom;
692
693                 chatroom = l->data;
694
695                 if (account == empathy_chatroom_get_account (chatroom)) {
696                         chatrooms = g_list_append (chatrooms, chatroom);
697                 }
698         }
699
700         return chatrooms;
701 }
702
703 guint
704 empathy_chatroom_manager_get_count (EmpathyChatroomManager *manager,
705                                    TpAccount *account)
706 {
707         EmpathyChatroomManagerPriv *priv;
708         GList                     *l;
709         guint                      count = 0;
710
711         g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), 0);
712
713         priv = GET_PRIV (manager);
714
715         if (!account) {
716                 return g_list_length (priv->chatrooms);
717         }
718
719         for (l = priv->chatrooms; l; l = l->next) {
720                 EmpathyChatroom *chatroom;
721
722                 chatroom = l->data;
723
724                 if (account == empathy_chatroom_get_account (chatroom)) {
725                         count++;
726                 }
727         }
728
729         return count;
730 }
731
732 static void
733 chatroom_manager_chat_destroyed_cb (EmpathyTpChat *chat,
734   gpointer manager)
735 {
736   EmpathyChatroomManagerPriv *priv = GET_PRIV (manager);
737   GList *l;
738
739   for (l = priv->chatrooms; l; l = l->next)
740     {
741       EmpathyChatroom *chatroom = l->data;
742
743       if (empathy_chatroom_get_tp_chat (chatroom) != chat)
744         continue;
745
746       empathy_chatroom_set_tp_chat (chatroom, NULL);
747
748       if (!empathy_chatroom_is_favorite (chatroom))
749         {
750           /* Remove the chatroom from the list, unless it's in the list of
751            * favourites..
752            * FIXME this policy should probably not be in libempathy */
753           chatroom_manager_remove_link (manager, l);
754         }
755
756       break;
757     }
758 }
759
760 /* Called by EmpathyChatManager when we are handling a new group chat */
761 void
762 empathy_chatroom_manager_chat_handled (EmpathyChatroomManager *self,
763     EmpathyTpChat *chat,
764     TpAccount *account)
765 {
766   EmpathyChatroom *chatroom;
767   const gchar *roomname;
768
769   roomname = empathy_tp_chat_get_id (chat);
770
771   chatroom = empathy_chatroom_manager_find (self, account, roomname);
772
773   if (chatroom == NULL)
774     {
775       chatroom = empathy_chatroom_new_full (account, roomname, roomname,
776         FALSE);
777       empathy_chatroom_set_tp_chat (chatroom, chat);
778       empathy_chatroom_manager_add (self, chatroom);
779       g_object_unref (chatroom);
780     }
781   else
782     {
783         empathy_chatroom_set_tp_chat (chatroom, chat);
784     }
785
786   /* A TpChat is always destroyed as it only gets unreffed after the channel
787    * has been invalidated in the dispatcher..  */
788   g_signal_connect (chat, "destroy",
789     G_CALLBACK (chatroom_manager_chat_destroyed_cb),
790     self);
791 }