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