rename text/{persona,individual}-id as they are not standard
[empathy-mirror.git] / libempathy / empathy-chatroom-manager.c
blob043f8a8297f4d293dcf20e3f076ff41dbcb9797a
1 /*
2 * Copyright (C) 2004-2007 Imendio AB
3 * Copyright (C) 2007-2010 Collabora Ltd.
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.
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.
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
20 * Authors: Xavier Claessens <xclaesse@gmail.com>
21 * Martyn Russell <martyn@imendio.com>
24 #include "config.h"
26 #include <string.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
30 #include <libxml/parser.h>
31 #include <libxml/tree.h>
33 #include <telepathy-glib/account-manager.h>
34 #include <telepathy-glib/interfaces.h>
35 #include <telepathy-glib/simple-observer.h>
36 #include <telepathy-glib/util.h>
38 #include "empathy-client-factory.h"
39 #include "empathy-tp-chat.h"
40 #include "empathy-chatroom-manager.h"
41 #include "empathy-utils.h"
43 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
44 #include "empathy-debug.h"
46 #define CHATROOMS_XML_FILENAME "chatrooms.xml"
47 #define CHATROOMS_DTD_FILENAME "empathy-chatroom-manager.dtd"
48 #define SAVE_TIMER 4
50 static EmpathyChatroomManager *chatroom_manager_singleton = NULL;
52 static void observe_channels_cb (TpSimpleObserver *observer,
53 TpAccount *account,
54 TpConnection *connection,
55 GList *channels,
56 TpChannelDispatchOperation *dispatch_operation,
57 GList *requests,
58 TpObserveChannelsContext *context,
59 gpointer user_data);
61 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyChatroomManager)
62 typedef struct
64 GList *chatrooms;
65 gchar *file;
66 TpAccountManager *account_manager;
68 /* source id of the autosave timer */
69 gint save_timer_id;
70 gboolean ready;
71 GFileMonitor *monitor;
72 gboolean writing;
74 TpBaseClient *observer;
75 } EmpathyChatroomManagerPriv;
77 enum {
78 CHATROOM_ADDED,
79 CHATROOM_REMOVED,
80 LAST_SIGNAL
83 static guint signals[LAST_SIGNAL];
85 /* properties */
86 enum
88 PROP_FILE = 1,
89 PROP_READY,
90 LAST_PROPERTY
93 G_DEFINE_TYPE (EmpathyChatroomManager, empathy_chatroom_manager, G_TYPE_OBJECT);
96 * API to save/load and parse the chatrooms file.
99 static gboolean
100 chatroom_manager_file_save (EmpathyChatroomManager *manager)
102 EmpathyChatroomManagerPriv *priv;
103 xmlDocPtr doc;
104 xmlNodePtr root;
105 GList *l;
107 priv = GET_PRIV (manager);
109 priv->writing = TRUE;
111 doc = xmlNewDoc ((const xmlChar *) "1.0");
112 root = xmlNewNode (NULL, (const xmlChar *) "chatrooms");
113 xmlDocSetRootElement (doc, root);
115 for (l = priv->chatrooms; l; l = l->next)
117 EmpathyChatroom *chatroom;
118 xmlNodePtr node;
119 const gchar *account_id;
121 chatroom = l->data;
123 if (!empathy_chatroom_is_favorite (chatroom))
124 continue;
126 account_id = tp_proxy_get_object_path (empathy_chatroom_get_account (
127 chatroom));
129 node = xmlNewChild (root, NULL, (const xmlChar *) "chatroom", NULL);
130 xmlNewTextChild (node, NULL, (const xmlChar *) "name",
131 (const xmlChar *) empathy_chatroom_get_name (chatroom));
132 xmlNewTextChild (node, NULL, (const xmlChar *) "room",
133 (const xmlChar *) empathy_chatroom_get_room (chatroom));
134 xmlNewTextChild (node, NULL, (const xmlChar *) "account",
135 (const xmlChar *) account_id);
136 xmlNewTextChild (node, NULL, (const xmlChar *) "auto_connect",
137 empathy_chatroom_get_auto_connect (chatroom) ?
138 (const xmlChar *) "yes" : (const xmlChar *) "no");
139 xmlNewTextChild (node, NULL, (const xmlChar *) "always_urgent",
140 empathy_chatroom_is_always_urgent (chatroom) ?
141 (const xmlChar *) "yes" : (const xmlChar *) "no");
144 /* Make sure the XML is indented properly */
145 xmlIndentTreeOutput = 1;
147 DEBUG ("Saving file:'%s'", priv->file);
148 xmlSaveFormatFileEnc (priv->file, doc, "utf-8", 1);
149 xmlFreeDoc (doc);
151 xmlMemoryDump ();
153 priv->writing = FALSE;
154 return TRUE;
157 static gboolean
158 save_timeout (EmpathyChatroomManager *self)
160 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
162 priv->save_timer_id = 0;
163 chatroom_manager_file_save (self);
165 return FALSE;
168 static void
169 reset_save_timeout (EmpathyChatroomManager *self)
171 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
173 if (priv->save_timer_id > 0)
174 g_source_remove (priv->save_timer_id);
176 priv->save_timer_id = g_timeout_add_seconds (SAVE_TIMER,
177 (GSourceFunc) save_timeout, self);
180 static void
181 chatroom_changed_cb (EmpathyChatroom *chatroom,
182 GParamSpec *spec,
183 EmpathyChatroomManager *self)
185 reset_save_timeout (self);
188 static void
189 add_chatroom (EmpathyChatroomManager *self,
190 EmpathyChatroom *chatroom)
192 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
194 priv->chatrooms = g_list_prepend (priv->chatrooms, g_object_ref (chatroom));
196 /* Watch only those properties which are exported in the save file */
197 g_signal_connect (chatroom, "notify::name",
198 G_CALLBACK (chatroom_changed_cb), self);
199 g_signal_connect (chatroom, "notify::room",
200 G_CALLBACK (chatroom_changed_cb), self);
201 g_signal_connect (chatroom, "notify::account",
202 G_CALLBACK (chatroom_changed_cb), self);
203 g_signal_connect (chatroom, "notify::auto-connect",
204 G_CALLBACK (chatroom_changed_cb), self);
205 g_signal_connect (chatroom, "notify::always_urgent",
206 G_CALLBACK (chatroom_changed_cb), self);
209 static void
210 chatroom_manager_parse_chatroom (EmpathyChatroomManager *manager,
211 xmlNodePtr node)
213 EmpathyChatroom *chatroom = NULL;
214 TpAccount *account;
215 xmlNodePtr child;
216 gchar *str;
217 gchar *name;
218 gchar *room;
219 gchar *account_id;
220 gboolean auto_connect;
221 gboolean always_urgent;
222 EmpathyClientFactory *factory;
223 GError *error = NULL;
225 /* default values. */
226 name = NULL;
227 room = NULL;
228 auto_connect = TRUE;
229 always_urgent = FALSE;
230 account_id = NULL;
232 for (child = node->children; child; child = child->next)
234 gchar *tag;
236 if (xmlNodeIsText (child))
237 continue;
239 tag = (gchar *) child->name;
240 str = (gchar *) xmlNodeGetContent (child);
242 if (strcmp (tag, "name") == 0)
244 name = g_strdup (str);
246 else if (strcmp (tag, "room") == 0)
248 room = g_strdup (str);
250 else if (strcmp (tag, "auto_connect") == 0)
252 if (strcmp (str, "yes") == 0)
253 auto_connect = TRUE;
254 else
255 auto_connect = FALSE;
257 else if (!tp_strdiff (tag, "always_urgent"))
259 if (strcmp (str, "yes") == 0)
260 always_urgent = TRUE;
261 else
262 always_urgent = FALSE;
264 else if (strcmp (tag, "account") == 0)
266 account_id = g_strdup (str);
269 xmlFree (str);
272 /* account has to be a valid Account object path */
273 if (!tp_dbus_check_valid_object_path (account_id, NULL) ||
274 !g_str_has_prefix (account_id, TP_ACCOUNT_OBJECT_PATH_BASE))
275 goto out;
277 factory = empathy_client_factory_dup ();
279 account = tp_simple_client_factory_ensure_account (
280 TP_SIMPLE_CLIENT_FACTORY (factory), account_id, NULL, &error);
281 g_object_unref (factory);
283 if (account == NULL)
285 DEBUG ("Failed to create account: %s", error->message);
286 g_error_free (error);
288 g_free (name);
289 g_free (room);
290 g_free (account_id);
291 return;
294 chatroom = empathy_chatroom_new_full (account, room, name, auto_connect);
295 empathy_chatroom_set_favorite (chatroom, TRUE);
296 empathy_chatroom_set_always_urgent (chatroom, always_urgent);
297 add_chatroom (manager, chatroom);
298 g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom);
300 out:
301 g_free (name);
302 g_free (room);
303 g_free (account_id);
304 tp_clear_object (&chatroom);
307 static gboolean
308 chatroom_manager_file_parse (EmpathyChatroomManager *manager,
309 const gchar *filename)
311 EmpathyChatroomManagerPriv *priv;
312 xmlParserCtxtPtr ctxt;
313 xmlDocPtr doc;
314 xmlNodePtr chatrooms;
315 xmlNodePtr node;
317 priv = GET_PRIV (manager);
319 DEBUG ("Attempting to parse file:'%s'...", filename);
321 ctxt = xmlNewParserCtxt ();
323 /* Parse and validate the file. */
324 doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
325 if (doc == NULL)
327 g_warning ("Failed to parse file:'%s'", filename);
328 xmlFreeParserCtxt (ctxt);
329 return FALSE;
332 if (!empathy_xml_validate (doc, CHATROOMS_DTD_FILENAME))
334 g_warning ("Failed to validate file:'%s'", filename);
335 xmlFreeDoc (doc);
336 xmlFreeParserCtxt (ctxt);
337 return FALSE;
340 /* The root node, chatrooms. */
341 chatrooms = xmlDocGetRootElement (doc);
343 for (node = chatrooms->children; node; node = node->next)
345 if (strcmp ((gchar *) node->name, "chatroom") == 0)
346 chatroom_manager_parse_chatroom (manager, node);
349 DEBUG ("Parsed %d chatrooms", g_list_length (priv->chatrooms));
351 xmlFreeDoc (doc);
352 xmlFreeParserCtxt (ctxt);
354 return TRUE;
357 static gboolean
358 chatroom_manager_get_all (EmpathyChatroomManager *manager)
360 EmpathyChatroomManagerPriv *priv;
362 priv = GET_PRIV (manager);
364 /* read file in */
365 if (g_file_test (priv->file, G_FILE_TEST_EXISTS) &&
366 !chatroom_manager_file_parse (manager, priv->file))
367 return FALSE;
369 if (!priv->ready)
371 priv->ready = TRUE;
372 g_object_notify (G_OBJECT (manager), "ready");
375 return TRUE;
378 static void
379 empathy_chatroom_manager_get_property (GObject *object,
380 guint property_id,
381 GValue *value,
382 GParamSpec *pspec)
384 EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object);
385 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
387 switch (property_id)
389 case PROP_FILE:
390 g_value_set_string (value, priv->file);
391 break;
392 case PROP_READY:
393 g_value_set_boolean (value, priv->ready);
394 break;
395 default:
396 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
397 break;
401 static void
402 empathy_chatroom_manager_set_property (GObject *object,
403 guint property_id,
404 const GValue *value,
405 GParamSpec *pspec)
407 EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object);
408 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
410 switch (property_id)
412 case PROP_FILE:
413 g_free (priv->file);
414 priv->file = g_value_dup_string (value);
415 break;
416 default:
417 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
418 break;
422 static void
423 chatroom_manager_dispose (GObject *object)
425 EmpathyChatroomManagerPriv *priv;
427 priv = GET_PRIV (object);
429 tp_clear_object (&priv->observer);
430 tp_clear_object (&priv->monitor);
432 (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->dispose) (object);
435 static void
436 clear_chatrooms (EmpathyChatroomManager *self)
438 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
439 GList *l, *tmp;
441 tmp = priv->chatrooms;
443 /* Unreffing the chatroom may result in destroying the underlying
444 * EmpathyTpChat which will fire the invalidated signal and so make us
445 * re-call this function. We already set priv->chatrooms to NULL so we won't
446 * try to destroy twice the same objects. */
447 priv->chatrooms = NULL;
449 for (l = tmp; l != NULL; l = g_list_next (l))
451 EmpathyChatroom *chatroom = l->data;
453 g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb,
454 self);
455 g_signal_emit (self, signals[CHATROOM_REMOVED], 0, chatroom);
457 g_object_unref (chatroom);
460 g_list_free (tmp);
463 static void
464 chatroom_manager_finalize (GObject *object)
466 EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (object);
467 EmpathyChatroomManagerPriv *priv;
469 priv = GET_PRIV (object);
471 g_object_unref (priv->account_manager);
473 if (priv->save_timer_id > 0)
475 /* have to save before destroy the object */
476 g_source_remove (priv->save_timer_id);
477 priv->save_timer_id = 0;
478 chatroom_manager_file_save (self);
481 clear_chatrooms (self);
483 g_free (priv->file);
485 (G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->finalize) (object);
488 static void
489 file_changed_cb (GFileMonitor *monitor,
490 GFile *file,
491 GFile *other_file,
492 GFileMonitorEvent event_type,
493 gpointer user_data)
495 EmpathyChatroomManager *self = user_data;
496 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
498 if (event_type != G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT)
499 return;
501 if (priv->writing)
502 return;
504 DEBUG ("chatrooms file changed; reloading list");
506 clear_chatrooms (self);
507 chatroom_manager_get_all (self);
510 static void
511 account_manager_ready_cb (GObject *source_object,
512 GAsyncResult *result,
513 gpointer user_data)
515 EmpathyChatroomManager *self = EMPATHY_CHATROOM_MANAGER (user_data);
516 EmpathyChatroomManagerPriv *priv = GET_PRIV (self);
517 TpAccountManager *manager = TP_ACCOUNT_MANAGER (source_object);
518 GError *error = NULL;
519 GFile *file = NULL;
521 if (!tp_account_manager_prepare_finish (manager, result, &error))
523 DEBUG ("Failed to prepare account manager: %s", error->message);
524 g_error_free (error);
525 goto out;
528 chatroom_manager_get_all (self);
530 /* Set up file monitor */
531 file = g_file_new_for_path (priv->file);
533 priv->monitor = g_file_monitor (file, 0, NULL, &error);
534 if (priv->monitor == NULL)
536 DEBUG ("Failed to create file monitor on %s: %s", priv->file,
537 error->message);
539 g_error_free (error);
540 goto out;
543 g_signal_connect (priv->monitor, "changed", G_CALLBACK (file_changed_cb),
544 self);
546 out:
547 tp_clear_object (&file);
548 g_object_unref (self);
551 static GObject *
552 empathy_chatroom_manager_constructor (GType type,
553 guint n_props,
554 GObjectConstructParam *props)
556 GObject *obj;
557 EmpathyChatroomManager *self;
558 EmpathyChatroomManagerPriv *priv;
559 GError *error = NULL;
561 if (chatroom_manager_singleton != NULL)
562 return g_object_ref (chatroom_manager_singleton);
564 /* Parent constructor chain */
565 obj = G_OBJECT_CLASS (empathy_chatroom_manager_parent_class)->
566 constructor (type, n_props, props);
568 self = EMPATHY_CHATROOM_MANAGER (obj);
569 priv = GET_PRIV (self);
571 priv->ready = FALSE;
573 chatroom_manager_singleton = self;
574 g_object_add_weak_pointer (obj, (gpointer) &chatroom_manager_singleton);
576 priv->account_manager = tp_account_manager_dup ();
578 tp_account_manager_prepare_async (priv->account_manager, NULL,
579 account_manager_ready_cb, g_object_ref (self));
581 if (priv->file == NULL)
583 /* Set the default file path */
584 gchar *dir;
586 dir = g_build_filename (g_get_user_config_dir (), PACKAGE_NAME, NULL);
587 if (!g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
588 g_mkdir_with_parents (dir, S_IRUSR | S_IWUSR | S_IXUSR);
590 priv->file = g_build_filename (dir, CHATROOMS_XML_FILENAME, NULL);
591 g_free (dir);
594 /* Setup a room observer */
595 priv->observer = tp_simple_observer_new_with_am (priv->account_manager, TRUE,
596 "Empathy.ChatroomManager", TRUE, observe_channels_cb, self, NULL);
598 tp_base_client_take_observer_filter (priv->observer, tp_asv_new (
599 TP_PROP_CHANNEL_CHANNEL_TYPE, G_TYPE_STRING,
600 TP_IFACE_CHANNEL_TYPE_TEXT,
601 TP_PROP_CHANNEL_TARGET_HANDLE_TYPE, G_TYPE_UINT,
602 TP_HANDLE_TYPE_ROOM,
603 NULL));
605 if (!tp_base_client_register (priv->observer, &error))
607 g_critical ("Failed to register Observer: %s", error->message);
609 g_error_free (error);
612 return obj;
615 static void
616 empathy_chatroom_manager_class_init (EmpathyChatroomManagerClass *klass)
618 GObjectClass *object_class = G_OBJECT_CLASS (klass);
619 GParamSpec *param_spec;
621 object_class->constructor = empathy_chatroom_manager_constructor;
622 object_class->get_property = empathy_chatroom_manager_get_property;
623 object_class->set_property = empathy_chatroom_manager_set_property;
624 object_class->dispose = chatroom_manager_dispose;
625 object_class->finalize = chatroom_manager_finalize;
627 param_spec = g_param_spec_string (
628 "file",
629 "path of the favorite file",
630 "The path of the XML file containing user's favorites",
631 NULL,
632 G_PARAM_CONSTRUCT_ONLY |
633 G_PARAM_READWRITE |
634 G_PARAM_STATIC_NAME |
635 G_PARAM_STATIC_NICK |
636 G_PARAM_STATIC_BLURB);
637 g_object_class_install_property (object_class, PROP_FILE, param_spec);
639 param_spec = g_param_spec_boolean (
640 "ready",
641 "whether the manager is ready yet",
642 "whether the manager is ready yet",
643 FALSE,
644 G_PARAM_READABLE);
645 g_object_class_install_property (object_class, PROP_READY, param_spec);
647 signals[CHATROOM_ADDED] = g_signal_new ("chatroom-added",
648 G_TYPE_FROM_CLASS (klass),
649 G_SIGNAL_RUN_LAST,
650 0, NULL, NULL,
651 g_cclosure_marshal_VOID__OBJECT,
652 G_TYPE_NONE,
653 1, EMPATHY_TYPE_CHATROOM);
655 signals[CHATROOM_REMOVED] = g_signal_new ("chatroom-removed",
656 G_TYPE_FROM_CLASS (klass),
657 G_SIGNAL_RUN_LAST,
658 0, NULL, NULL,
659 g_cclosure_marshal_VOID__OBJECT,
660 G_TYPE_NONE,
661 1, EMPATHY_TYPE_CHATROOM);
663 g_type_class_add_private (object_class, sizeof (EmpathyChatroomManagerPriv));
666 static void
667 empathy_chatroom_manager_init (EmpathyChatroomManager *manager)
669 EmpathyChatroomManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
670 EMPATHY_TYPE_CHATROOM_MANAGER, EmpathyChatroomManagerPriv);
672 manager->priv = priv;
675 EmpathyChatroomManager *
676 empathy_chatroom_manager_dup_singleton (const gchar *file)
678 return EMPATHY_CHATROOM_MANAGER (g_object_new (EMPATHY_TYPE_CHATROOM_MANAGER,
679 "file", file, NULL));
682 gboolean
683 empathy_chatroom_manager_add (EmpathyChatroomManager *manager,
684 EmpathyChatroom *chatroom)
686 g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), FALSE);
687 g_return_val_if_fail (EMPATHY_IS_CHATROOM (chatroom), FALSE);
689 /* don't add more than once */
690 if (!empathy_chatroom_manager_find (manager,
691 empathy_chatroom_get_account (chatroom),
692 empathy_chatroom_get_room (chatroom)))
694 add_chatroom (manager, chatroom);
696 if (empathy_chatroom_is_favorite (chatroom))
697 reset_save_timeout (manager);
699 g_signal_emit (manager, signals[CHATROOM_ADDED], 0, chatroom);
700 return TRUE;
703 return FALSE;
706 static void
707 chatroom_manager_remove_link (EmpathyChatroomManager *manager,
708 GList *l)
710 EmpathyChatroomManagerPriv *priv;
711 EmpathyChatroom *chatroom;
713 priv = GET_PRIV (manager);
715 chatroom = l->data;
717 if (empathy_chatroom_is_favorite (chatroom))
718 reset_save_timeout (manager);
720 priv->chatrooms = g_list_delete_link (priv->chatrooms, l);
722 g_signal_emit (manager, signals[CHATROOM_REMOVED], 0, chatroom);
723 g_signal_handlers_disconnect_by_func (chatroom, chatroom_changed_cb, manager);
725 g_object_unref (chatroom);
728 void
729 empathy_chatroom_manager_remove (EmpathyChatroomManager *manager,
730 EmpathyChatroom *chatroom)
732 EmpathyChatroomManagerPriv *priv;
733 GList *l;
735 g_return_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager));
736 g_return_if_fail (EMPATHY_IS_CHATROOM (chatroom));
738 priv = GET_PRIV (manager);
740 for (l = priv->chatrooms; l; l = l->next)
742 EmpathyChatroom *this_chatroom;
744 this_chatroom = l->data;
746 if (this_chatroom == chatroom ||
747 empathy_chatroom_equal (chatroom, this_chatroom))
749 chatroom_manager_remove_link (manager, l);
750 break;
755 EmpathyChatroom *
756 empathy_chatroom_manager_find (EmpathyChatroomManager *manager,
757 TpAccount *account,
758 const gchar *room)
760 EmpathyChatroomManagerPriv *priv;
761 GList *l;
763 g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), NULL);
764 g_return_val_if_fail (room != NULL, NULL);
766 priv = GET_PRIV (manager);
768 for (l = priv->chatrooms; l; l = l->next)
770 EmpathyChatroom *chatroom;
771 TpAccount *this_account;
772 const gchar *this_room;
774 chatroom = l->data;
775 this_account = empathy_chatroom_get_account (chatroom);
776 this_room = empathy_chatroom_get_room (chatroom);
778 if (this_account && this_room && account == this_account
779 && strcmp (this_room, room) == 0)
780 return chatroom;
783 return NULL;
786 EmpathyChatroom *
787 empathy_chatroom_manager_ensure_chatroom (EmpathyChatroomManager *manager,
788 TpAccount *account,
789 const gchar *room,
790 const gchar *name)
792 EmpathyChatroom *chatroom;
794 chatroom = empathy_chatroom_manager_find (manager, account, room);
796 if (chatroom)
798 return g_object_ref (chatroom);
800 else
802 chatroom = empathy_chatroom_new_full (account,
803 room,
804 name,
805 FALSE);
806 empathy_chatroom_manager_add (manager, chatroom);
807 return chatroom;
811 GList *
812 empathy_chatroom_manager_get_chatrooms (EmpathyChatroomManager *manager,
813 TpAccount *account)
815 EmpathyChatroomManagerPriv *priv;
816 GList *chatrooms, *l;
818 g_return_val_if_fail (EMPATHY_IS_CHATROOM_MANAGER (manager), NULL);
820 priv = GET_PRIV (manager);
822 if (!account)
823 return g_list_copy (priv->chatrooms);
825 chatrooms = NULL;
826 for (l = priv->chatrooms; l; l = l->next)
828 EmpathyChatroom *chatroom;
830 chatroom = l->data;
832 if (account == empathy_chatroom_get_account (chatroom))
833 chatrooms = g_list_append (chatrooms, chatroom);
836 return chatrooms;
839 static void
840 chatroom_manager_chat_invalidated_cb (EmpathyTpChat *chat,
841 guint domain,
842 gint code,
843 gchar *message,
844 gpointer manager)
846 EmpathyChatroomManagerPriv *priv = GET_PRIV (manager);
847 GList *l;
849 for (l = priv->chatrooms; l; l = l->next)
851 EmpathyChatroom *chatroom = l->data;
853 if (empathy_chatroom_get_tp_chat (chatroom) != chat)
854 continue;
856 empathy_chatroom_set_tp_chat (chatroom, NULL);
858 if (!empathy_chatroom_is_favorite (chatroom))
860 /* Remove the chatroom from the list, unless it's in the list of
861 * favourites..
862 * FIXME this policy should probably not be in libempathy */
863 chatroom_manager_remove_link (manager, l);
866 break;
870 static void
871 observe_channels_cb (TpSimpleObserver *observer,
872 TpAccount *account,
873 TpConnection *connection,
874 GList *channels,
875 TpChannelDispatchOperation *dispatch_operation,
876 GList *requests,
877 TpObserveChannelsContext *context,
878 gpointer user_data)
880 EmpathyChatroomManager *self = user_data;
881 GList *l;
883 for (l = channels; l != NULL; l = g_list_next (l))
885 EmpathyTpChat *tp_chat = l->data;
886 const gchar *roomname;
887 EmpathyChatroom *chatroom;
889 if (tp_proxy_get_invalidated ((TpChannel *) tp_chat) != NULL)
890 continue;
892 if (!EMPATHY_IS_TP_CHAT (tp_chat))
893 continue;
895 roomname = empathy_tp_chat_get_id (tp_chat);
896 chatroom = empathy_chatroom_manager_find (self, account, roomname);
898 if (chatroom == NULL)
900 chatroom = empathy_chatroom_new_full (account, roomname, roomname,
901 FALSE);
902 empathy_chatroom_manager_add (self, chatroom);
903 g_object_unref (chatroom);
906 empathy_chatroom_set_tp_chat (chatroom, tp_chat);
908 g_signal_connect (tp_chat, "invalidated",
909 G_CALLBACK (chatroom_manager_chat_invalidated_cb),
910 self);
913 tp_observe_channels_context_accept (context);