]> git.0d.be Git - empathy.git/blob - libempathy-gtk/gossip-chat-manager.c
[darcs-to-svn @ Syncing message history from gossip]
[empathy.git] / libempathy-gtk / gossip-chat-manager.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2004-2007 Imendio AB
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * Authors: Martyn Russell <martyn@imendio.com>
21  */
22
23 #include "config.h"
24
25 #include <string.h>
26
27 #include <glib/gi18n.h>
28
29 #include <libgossip/gossip-account.h>
30 #include <libgossip/gossip-event.h>
31 #include <libgossip/gossip-session.h>
32 #include <libgossip/gossip-message.h>
33 #include <libgossip/gossip-debug.h>
34 #include <libgossip/gossip-event-manager.h>
35
36 #include "gossip-app.h"
37 #include "gossip-chat.h"
38 #include "gossip-chat-manager.h"
39
40 #define DEBUG_DOMAIN "ChatManager"
41
42 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GOSSIP_TYPE_CHAT_MANAGER, GossipChatManagerPriv))
43
44 typedef struct _GossipChatManagerPriv GossipChatManagerPriv;
45
46 struct _GossipChatManagerPriv {
47         GHashTable *chats;
48         GHashTable *events;
49 };
50
51 static void chat_manager_finalize           (GObject             *object);
52 static void chat_manager_new_message_cb     (GossipSession       *session,
53                                              GossipMessage       *msg,
54                                              GossipChatManager   *manager);
55 static void chat_manager_event_activated_cb (GossipEventManager  *event_manager,
56                                              GossipEvent         *event,
57                                              GObject             *object);
58 static void chat_manager_get_chats_foreach  (GossipContact       *contact,
59                                              GossipPrivateChat   *chat,
60                                              GList              **chats);
61 static void chat_manager_chat_removed_cb    (GossipChatManager   *manager,
62                                              GossipChat          *chat,
63                                              gboolean             is_last_ref);
64
65 G_DEFINE_TYPE (GossipChatManager, gossip_chat_manager, G_TYPE_OBJECT);
66
67 static void
68 gossip_chat_manager_class_init (GossipChatManagerClass *class)
69 {
70         GObjectClass *object_class;
71
72         object_class = G_OBJECT_CLASS (class);
73
74         object_class->finalize = chat_manager_finalize;
75
76         g_type_class_add_private (object_class, sizeof (GossipChatManagerPriv));
77 }
78
79 static void
80 gossip_chat_manager_init (GossipChatManager *manager)
81 {
82         GossipChatManagerPriv *priv;
83
84         priv = GET_PRIV (manager);
85
86         priv->chats = g_hash_table_new_full (gossip_contact_hash,
87                                              gossip_contact_equal,
88                                              (GDestroyNotify) g_object_unref,
89                                              (GDestroyNotify) g_object_unref);
90
91         priv->events = g_hash_table_new_full (gossip_contact_hash,
92                                               gossip_contact_equal,
93                                               (GDestroyNotify) g_object_unref,
94                                               (GDestroyNotify) g_object_unref);
95
96         /* Connect to signals on GossipSession to listen for new messages */
97         g_signal_connect (gossip_app_get_session (),
98                           "new-message",
99                           G_CALLBACK (chat_manager_new_message_cb),
100                           manager);
101 }
102
103 static void
104 chat_manager_finalize (GObject *object)
105 {
106         GossipChatManagerPriv *priv;
107
108         priv = GET_PRIV (object);
109
110         g_hash_table_destroy (priv->chats);
111         g_hash_table_destroy (priv->events);
112
113         G_OBJECT_CLASS (gossip_chat_manager_parent_class)->finalize (object);
114 }
115
116 static void
117 chat_manager_new_message_cb (GossipSession     *session,
118                              GossipMessage     *message,
119                              GossipChatManager *manager)
120 {
121         GossipChatManagerPriv *priv;
122         GossipPrivateChat     *chat;
123         GossipContact         *sender;
124         GossipEvent           *event = NULL;
125         GossipEvent           *old_event;
126
127         priv = GET_PRIV (manager);
128
129         sender = gossip_message_get_sender (message);
130         chat = g_hash_table_lookup (priv->chats, sender);
131
132         old_event = g_hash_table_lookup (priv->events, sender);
133
134         /* Add event to event manager if one doesn't exist already. */
135         if (!chat) {
136                 gossip_debug (DEBUG_DOMAIN, "New chat for: %s",
137                               gossip_contact_get_id (sender));
138                 chat = gossip_chat_manager_get_chat (manager, sender);
139
140                 if (!old_event) {
141                         event = gossip_event_new (GOSSIP_EVENT_NEW_MESSAGE);
142                 }
143         } else {
144                 GossipChatWindow *window;
145
146                 window = gossip_chat_get_window (GOSSIP_CHAT (chat));
147
148                 if (!window && !old_event) {
149                         event = gossip_event_new (GOSSIP_EVENT_NEW_MESSAGE);
150                 }
151         }
152
153         gossip_private_chat_append_message (chat, message);
154
155         if (event) {
156                 gchar *str;
157
158                 str = g_strdup_printf (_("New message from %s"),
159                                        gossip_contact_get_name (sender));
160                 g_object_set (event,
161                               "message", str,
162                               "data", message,
163                               NULL);
164                 g_free (str);
165
166                 gossip_event_manager_add (gossip_app_get_event_manager (),
167                                           event,
168                                           chat_manager_event_activated_cb,
169                                           G_OBJECT (manager));
170
171                 g_hash_table_insert (priv->events,
172                                      g_object_ref (sender),
173                                      g_object_ref (event));
174         }
175 }
176
177 static void
178 chat_manager_event_activated_cb (GossipEventManager *event_manager,
179                                  GossipEvent        *event,
180                                  GObject            *object)
181 {
182         GossipMessage *message;
183         GossipContact *contact;
184
185         message = GOSSIP_MESSAGE (gossip_event_get_data (event));
186         contact = gossip_message_get_sender (message);
187
188         gossip_chat_manager_show_chat (GOSSIP_CHAT_MANAGER (object), contact);
189 }
190
191 static void
192 chat_manager_get_chats_foreach (GossipContact      *contact,
193                                 GossipPrivateChat  *chat,
194                                 GList             **chats)
195 {
196         const gchar *contact_id;
197
198         contact_id = gossip_contact_get_id (contact);
199         *chats = g_list_prepend (*chats, g_strdup (contact_id));
200 }
201
202 GossipChatManager *
203 gossip_chat_manager_new (void)
204 {
205         return g_object_new (GOSSIP_TYPE_CHAT_MANAGER, NULL);
206 }
207
208 static void
209 chat_manager_chat_removed_cb (GossipChatManager *manager,
210                               GossipChat        *chat,
211                               gboolean           is_last_ref) 
212 {
213         GossipChatManagerPriv *priv;
214         GossipContact         *contact;
215
216         if (!is_last_ref) {
217                 return;
218         }
219         
220         priv = GET_PRIV (manager);
221         
222         contact = gossip_chat_get_contact (chat);
223
224         gossip_debug (DEBUG_DOMAIN, 
225                       "Removing an old chat:'%s'",
226                       gossip_contact_get_id (contact));
227
228         g_hash_table_remove (priv->chats, contact);
229 }                             
230
231 GossipPrivateChat *
232 gossip_chat_manager_get_chat (GossipChatManager *manager,
233                               GossipContact     *contact)
234 {
235         GossipChatManagerPriv *priv;
236         GossipPrivateChat     *chat;
237
238         g_return_val_if_fail (GOSSIP_IS_CHAT_MANAGER (manager), NULL);
239         g_return_val_if_fail (GOSSIP_IS_CONTACT (contact), NULL);
240
241         priv = GET_PRIV (manager);
242
243         chat = g_hash_table_lookup (priv->chats, contact);
244
245         if (!chat) {
246                 GossipSession *session;
247                 GossipAccount *account;
248                 GossipContact *own_contact;
249
250                 session = gossip_app_get_session ();
251                 account = gossip_contact_get_account (contact);
252                 own_contact = gossip_session_get_own_contact (session, account);
253
254                 chat = gossip_private_chat_new (own_contact, contact);
255                 g_hash_table_insert (priv->chats,
256                                      g_object_ref (contact),
257                                      chat);
258                 g_object_add_toggle_ref (G_OBJECT (chat),
259                                          (GToggleNotify) chat_manager_chat_removed_cb, 
260                                          manager);
261
262                 gossip_debug (DEBUG_DOMAIN, 
263                               "Creating a new chat:'%s'",
264                               gossip_contact_get_id (contact));
265         }
266
267         return chat;
268 }
269
270 GList *
271 gossip_chat_manager_get_chats (GossipChatManager *manager)
272 {
273         GossipChatManagerPriv *priv;
274         GList                 *chats = NULL;
275
276         g_return_val_if_fail (GOSSIP_IS_CHAT_MANAGER (manager), NULL);
277
278         priv = GET_PRIV (manager);
279
280         g_hash_table_foreach (priv->chats,
281                               (GHFunc) chat_manager_get_chats_foreach,
282                               &chats);
283
284         chats = g_list_sort (chats, (GCompareFunc) strcmp);
285
286         return chats;
287 }
288
289 void
290 gossip_chat_manager_remove_events (GossipChatManager *manager,
291                                    GossipContact     *contact)
292 {
293         GossipChatManagerPriv *priv;
294         GossipEvent           *event;
295
296         g_return_if_fail (GOSSIP_IS_CHAT_MANAGER (manager));
297         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
298
299         gossip_debug (DEBUG_DOMAIN, 
300                       "Removing events for contact:'%s'",
301                       gossip_contact_get_id (contact));
302
303         priv = GET_PRIV (manager);
304
305         event = g_hash_table_lookup (priv->events, contact);
306         if (event) {
307                 gossip_event_manager_remove (gossip_app_get_event_manager (),
308                                              event, G_OBJECT (manager));
309                 g_hash_table_remove (priv->events, contact);
310         }
311 }
312
313 void
314 gossip_chat_manager_show_chat (GossipChatManager *manager,
315                                GossipContact     *contact)
316 {
317         GossipPrivateChat     *chat;
318
319         g_return_if_fail (GOSSIP_IS_CHAT_MANAGER (manager));
320         g_return_if_fail (GOSSIP_IS_CONTACT (contact));
321
322         chat = gossip_chat_manager_get_chat (manager, contact);
323
324         gossip_chat_present (GOSSIP_CHAT (chat));
325
326         gossip_chat_manager_remove_events(manager, contact);
327 }