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