]> git.0d.be Git - empathy.git/blob - libempathy/empathy-log-manager.c
Added empathy_message_get_unique_id & empathy_message_equal.
[empathy.git] / libempathy / empathy-log-manager.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 2003-2007 Imendio AB
4  * Copyright (C) 2007-2008 Collabora Ltd.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License as
8  * published by the Free Software Foundation; either version 2 of the
9  * License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21  * Authors: Xavier Claessens <xclaesse@gmail.com>
22  */
23
24 #include <config.h>
25
26 #include <string.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <glib/gstdio.h>
30
31 #include <telepathy-glib/util.h>
32
33 #include "empathy-log-manager.h"
34 #include "empathy-log-store-empathy.h"
35 #include "empathy-log-store.h"
36 #include "empathy-tp-chat.h"
37 #include "empathy-utils.h"
38
39 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
40 #include "empathy-debug.h"
41
42 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLogManager)
43 typedef struct
44 {
45   GList *stores;
46 } EmpathyLogManagerPriv;
47
48 G_DEFINE_TYPE (EmpathyLogManager, empathy_log_manager, G_TYPE_OBJECT);
49
50 static EmpathyLogManager * manager_singleton = NULL;
51
52 static void
53 log_manager_finalize (GObject *object)
54 {
55   EmpathyLogManagerPriv *priv;
56   GList *l;
57
58   priv = GET_PRIV (object);
59
60   for (l = priv->stores; l; l = l->next)
61     {
62       EmpathyLogStore *store = (EmpathyLogStore *) l->data;
63       g_object_unref (store);
64     }
65
66   g_list_free (priv->stores);
67 }
68
69 static GObject *
70 log_manager_constructor (GType type,
71                          guint n_props,
72                          GObjectConstructParam *props)
73 {
74   GObject *retval;
75   EmpathyLogManagerPriv *priv;
76
77   if (manager_singleton)
78     {
79       retval = g_object_ref (manager_singleton);
80     }
81   else
82     {
83       retval = G_OBJECT_CLASS (empathy_log_manager_parent_class)->constructor
84           (type, n_props, props);
85
86       manager_singleton = EMPATHY_LOG_MANAGER (retval);
87       g_object_add_weak_pointer (retval, (gpointer *) &manager_singleton);
88
89       priv = GET_PRIV (manager_singleton);
90
91       priv->stores = g_list_append (priv->stores,
92           g_object_new (EMPATHY_TYPE_LOG_STORE_EMPATHY, NULL));
93     }
94
95   return retval;
96 }
97
98 static void
99 empathy_log_manager_class_init (EmpathyLogManagerClass *klass)
100 {
101   GObjectClass *object_class = G_OBJECT_CLASS (klass);
102
103   object_class->constructor = log_manager_constructor;
104   object_class->finalize = log_manager_finalize;
105
106   g_type_class_add_private (object_class, sizeof (EmpathyLogManagerPriv));
107 }
108
109 static void
110 empathy_log_manager_init (EmpathyLogManager *manager)
111 {
112   EmpathyLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
113       EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv);
114
115   priv->stores = g_list_append (priv->stores,
116       g_object_new (EMPATHY_TYPE_LOG_STORE_EMPATHY, NULL));
117
118   manager->priv = priv;
119 }
120
121 EmpathyLogManager *
122 empathy_log_manager_dup_singleton (void)
123 {
124   return g_object_new (EMPATHY_TYPE_LOG_MANAGER, NULL);
125 }
126
127 gboolean
128 empathy_log_manager_add_message (EmpathyLogManager *manager,
129                                  const gchar *chat_id,
130                                  gboolean chatroom,
131                                  EmpathyMessage *message,
132                                  GError **error)
133 {
134   EmpathyLogManagerPriv *priv;
135   GList *l;
136   gboolean out = FALSE;
137   gboolean found = FALSE;
138
139   /* TODO: When multiple log stores appear with add_message implementations
140    * make this customisable. */
141   const gchar *add_store = "Empathy";
142
143   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
144   g_return_val_if_fail (chat_id != NULL, FALSE);
145   g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
146
147   priv = GET_PRIV (manager);
148
149   for (l = priv->stores; l; l = l->next)
150     {
151       if (!tp_strdiff (empathy_log_store_get_name (
152               EMPATHY_LOG_STORE (l->data)), add_store))
153         {
154           out = empathy_log_store_add_message (EMPATHY_LOG_STORE (l->data),
155               chat_id, chatroom, message, error);
156           found = TRUE;
157           break;
158         }
159     }
160
161   if (!found)
162     DEBUG ("Failed to find chosen log store to write to.");
163
164   return out;
165 }
166
167 gboolean
168 empathy_log_manager_exists (EmpathyLogManager *manager,
169                             McAccount *account,
170                             const gchar *chat_id,
171                             gboolean chatroom)
172 {
173   GList *l;
174   EmpathyLogManagerPriv *priv;
175
176   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
177   g_return_val_if_fail (MC_IS_ACCOUNT (account), FALSE);
178   g_return_val_if_fail (chat_id != NULL, FALSE);
179
180   priv = GET_PRIV (manager);
181
182   for (l = priv->stores; l; l = l->next)
183     {
184       if (empathy_log_store_exists (EMPATHY_LOG_STORE (l->data),
185             account, chat_id, chatroom))
186         return TRUE;
187     }
188
189   return FALSE;
190 }
191
192 static void
193 log_manager_get_dates_foreach (gpointer data,
194                                gpointer user_data)
195 {
196   /* g_list_first is needed in case an older date was last inserted */
197   GList *orig = g_list_first (user_data);
198
199   if (g_list_find_custom (orig, data, (GCompareFunc) strcmp))
200     orig = g_list_insert_sorted (orig, g_strdup (data), (GCompareFunc) strcmp);
201 }
202
203 GList *
204 empathy_log_manager_get_dates (EmpathyLogManager *manager,
205                                McAccount *account,
206                                const gchar *chat_id,
207                                gboolean chatroom)
208 {
209   GList *l, *out = NULL;
210   EmpathyLogManagerPriv *priv;
211
212   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
213   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
214   g_return_val_if_fail (chat_id != NULL, NULL);
215
216   priv = GET_PRIV (manager);
217
218   for (l = priv->stores; l; l = l->next)
219     {
220       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
221
222       if (!out)
223         out = empathy_log_store_get_dates (store, account, chat_id, chatroom);
224       else
225         {
226           GList *new = empathy_log_store_get_dates (store, account, chat_id,
227               chatroom);
228           g_list_foreach (new, log_manager_get_dates_foreach, out);
229
230           g_list_foreach (new, (GFunc) g_free, NULL);
231           g_list_free (new);
232
233           /* Similar reason for using g_list_first here as before */
234           out = g_list_first (out);
235         }
236     }
237
238   return out;
239 }
240
241 GList *
242 empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
243                                            McAccount *account,
244                                            const gchar *chat_id,
245                                            gboolean chatroom,
246                                            const gchar *date)
247 {
248   GList *l, *out = NULL;
249   EmpathyLogManagerPriv *priv;
250
251   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
252   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
253   g_return_val_if_fail (chat_id != NULL, NULL);
254
255   priv = GET_PRIV (manager);
256
257   for (l = priv->stores; l; l = l->next)
258     {
259       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
260
261       out = g_list_concat (out, empathy_log_store_get_messages_for_date (
262           store, account, chat_id, chatroom, date));
263     }
264
265   return out;
266 }
267
268 GList *
269 empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
270                                        McAccount *account,
271                                        const gchar *chat_id,
272                                        gboolean chatroom)
273 {
274   GList *messages = NULL;
275   GList *dates;
276   GList *l;
277
278   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
279   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
280   g_return_val_if_fail (chat_id != NULL, NULL);
281
282   dates = empathy_log_manager_get_dates (manager, account, chat_id, chatroom);
283
284   l = g_list_last (dates);
285   if (l)
286     messages = empathy_log_manager_get_messages_for_date (manager, account,
287         chat_id, chatroom, l->data);
288
289   g_list_foreach (dates, (GFunc) g_free, NULL);
290   g_list_free (dates);
291
292   return messages;
293 }
294
295 GList *
296 empathy_log_manager_get_chats (EmpathyLogManager *manager,
297                                McAccount *account)
298 {
299   GList *l, *out = NULL;
300   EmpathyLogManagerPriv *priv;
301
302   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
303   g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
304
305   priv = GET_PRIV (manager);
306
307   for (l = priv->stores; l; l = l->next)
308     {
309       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
310
311       out = g_list_concat (out,
312           empathy_log_store_get_chats (store, account));
313     }
314
315   return out;
316 }
317
318 GList *
319 empathy_log_manager_search_new (EmpathyLogManager *manager,
320                                 const gchar *text)
321 {
322   GList *l, *out = NULL;
323   EmpathyLogManagerPriv *priv;
324
325   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
326   g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL);
327
328   priv = GET_PRIV (manager);
329
330   for (l = priv->stores; l; l = l->next)
331     {
332       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
333
334       out = g_list_concat (out,
335           empathy_log_store_search_new (store, text));
336     }
337
338   return out;
339 }
340
341 void
342 empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit)
343 {
344   if (hit->account)
345     g_object_unref (hit->account);
346
347   g_free (hit->date);
348   g_free (hit->filename);
349   g_free (hit->chat_id);
350
351   g_slice_free (EmpathyLogSearchHit, hit);
352 }
353
354 void
355 empathy_log_manager_search_free (GList *hits)
356 {
357   GList *l;
358
359   for (l = hits; l; l = l->next)
360     {
361       empathy_log_manager_search_hit_free (l->data);
362     }
363
364   g_list_free (hits);
365 }
366
367 /* Format is just date, 20061201. */
368 gchar *
369 empathy_log_manager_get_date_readable (const gchar *date)
370 {
371   time_t t;
372
373   t = empathy_time_parse (date);
374
375   return empathy_time_to_string_local (t, "%a %d %b %Y");
376 }
377
378 static void
379 log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat,
380                                       EmpathyMessage *message,
381                                       EmpathyLogManager *log_manager)
382 {
383   GError *error = NULL;
384   TpHandleType handle_type;
385   TpChannel *channel;
386
387   channel = empathy_tp_chat_get_channel (tp_chat);
388   tp_channel_get_handle (channel, &handle_type);
389
390   if (!empathy_log_manager_add_message (log_manager,
391         tp_channel_get_identifier (channel),
392         handle_type == TP_HANDLE_TYPE_ROOM,
393         message, &error))
394     {
395       DEBUG ("Failed to write message: %s",
396           error ? error->message : "No error message");
397
398       if (error)
399         g_error_free (error);
400     }
401 }
402
403 static void
404 log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher,
405                                    EmpathyDispatchOperation *operation,
406                                    EmpathyLogManager *log_manager)
407 {
408   GQuark channel_type;
409
410   channel_type = empathy_dispatch_operation_get_channel_type_id (operation);
411
412   if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
413     {
414       EmpathyTpChat *tp_chat;
415
416       tp_chat = EMPATHY_TP_CHAT (
417           empathy_dispatch_operation_get_channel_wrapper (operation));
418
419       g_signal_connect (tp_chat, "message-received",
420           G_CALLBACK (log_manager_chat_received_message_cb), log_manager);
421     }
422 }
423
424
425 void
426 empathy_log_manager_observe (EmpathyLogManager *log_manager,
427                              EmpathyDispatcher *dispatcher)
428 {
429   g_signal_connect (dispatcher, "observe",
430       G_CALLBACK (log_manager_dispatcher_observe_cb), log_manager);
431 }