]> git.0d.be Git - empathy.git/blob - libempathy/empathy-log-manager.c
add myself to AUTHORS
[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., 51 Franklin St, Fifth Floor,
19  * Boston, MA  02110-1301  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 #include <telepathy-glib/interfaces.h>
33
34 #include "empathy-log-manager.h"
35 #include "empathy-log-store-empathy.h"
36 #include "empathy-log-store.h"
37 #include "empathy-tp-chat.h"
38 #include "empathy-utils.h"
39
40 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
41 #include "empathy-debug.h"
42
43 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLogManager)
44 typedef struct
45 {
46   GList *stores;
47 } EmpathyLogManagerPriv;
48
49 G_DEFINE_TYPE (EmpathyLogManager, empathy_log_manager, G_TYPE_OBJECT);
50
51 static EmpathyLogManager * manager_singleton = NULL;
52
53 static void
54 log_manager_finalize (GObject *object)
55 {
56   EmpathyLogManagerPriv *priv;
57
58   priv = GET_PRIV (object);
59
60   g_list_foreach (priv->stores, (GFunc) g_object_unref, NULL);
61   g_list_free (priv->stores);
62 }
63
64 static GObject *
65 log_manager_constructor (GType type,
66                          guint n_props,
67                          GObjectConstructParam *props)
68 {
69   GObject *retval;
70   EmpathyLogManagerPriv *priv;
71
72   if (manager_singleton)
73     {
74       retval = g_object_ref (manager_singleton);
75     }
76   else
77     {
78       retval = G_OBJECT_CLASS (empathy_log_manager_parent_class)->constructor
79           (type, n_props, props);
80
81       manager_singleton = EMPATHY_LOG_MANAGER (retval);
82       g_object_add_weak_pointer (retval, (gpointer *) &manager_singleton);
83
84       priv = GET_PRIV (manager_singleton);
85
86       priv->stores = g_list_append (priv->stores,
87           g_object_new (EMPATHY_TYPE_LOG_STORE_EMPATHY, NULL));
88     }
89
90   return retval;
91 }
92
93 static void
94 empathy_log_manager_class_init (EmpathyLogManagerClass *klass)
95 {
96   GObjectClass *object_class = G_OBJECT_CLASS (klass);
97
98   object_class->constructor = log_manager_constructor;
99   object_class->finalize = log_manager_finalize;
100
101   g_type_class_add_private (object_class, sizeof (EmpathyLogManagerPriv));
102 }
103
104 static void
105 empathy_log_manager_init (EmpathyLogManager *manager)
106 {
107   EmpathyLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager,
108       EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv);
109
110   manager->priv = priv;
111 }
112
113 EmpathyLogManager *
114 empathy_log_manager_dup_singleton (void)
115 {
116   return g_object_new (EMPATHY_TYPE_LOG_MANAGER, NULL);
117 }
118
119 gboolean
120 empathy_log_manager_add_message (EmpathyLogManager *manager,
121                                  const gchar *chat_id,
122                                  gboolean chatroom,
123                                  EmpathyMessage *message,
124                                  GError **error)
125 {
126   EmpathyLogManagerPriv *priv;
127   GList *l;
128   gboolean out = FALSE;
129   gboolean found = FALSE;
130
131   /* TODO: When multiple log stores appear with add_message implementations
132    * make this customisable. */
133   const gchar *add_store = "Empathy";
134
135   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
136   g_return_val_if_fail (chat_id != NULL, FALSE);
137   g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
138
139   priv = GET_PRIV (manager);
140
141   for (l = priv->stores; l; l = g_list_next (l))
142     {
143       if (!tp_strdiff (empathy_log_store_get_name (
144               EMPATHY_LOG_STORE (l->data)), add_store))
145         {
146           out = empathy_log_store_add_message (EMPATHY_LOG_STORE (l->data),
147               chat_id, chatroom, message, error);
148           found = TRUE;
149           break;
150         }
151     }
152
153   if (!found)
154     DEBUG ("Failed to find chosen log store to write to.");
155
156   return out;
157 }
158
159 gboolean
160 empathy_log_manager_exists (EmpathyLogManager *manager,
161                             TpAccount *account,
162                             const gchar *chat_id,
163                             gboolean chatroom)
164 {
165   GList *l;
166   EmpathyLogManagerPriv *priv;
167
168   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE);
169   g_return_val_if_fail (chat_id != NULL, FALSE);
170
171   priv = GET_PRIV (manager);
172
173   for (l = priv->stores; l; l = g_list_next (l))
174     {
175       if (empathy_log_store_exists (EMPATHY_LOG_STORE (l->data),
176             account, chat_id, chatroom))
177         return TRUE;
178     }
179
180   return FALSE;
181 }
182
183 GList *
184 empathy_log_manager_get_dates (EmpathyLogManager *manager,
185                                TpAccount *account,
186                                const gchar *chat_id,
187                                gboolean chatroom)
188 {
189   GList *l, *out = NULL;
190   EmpathyLogManagerPriv *priv;
191
192   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
193   g_return_val_if_fail (chat_id != NULL, NULL);
194
195   priv = GET_PRIV (manager);
196
197   for (l = priv->stores; l; l = g_list_next (l))
198     {
199       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
200       GList *new;
201
202       /* Insert dates of each store in the out list. Keep the out list sorted
203        * and avoid to insert dups. */
204       new = empathy_log_store_get_dates (store, account, chat_id, chatroom);
205       while (new)
206         {
207           if (g_list_find_custom (out, new->data, (GCompareFunc) strcmp))
208             g_free (new->data);
209           else
210             out = g_list_insert_sorted (out, new->data, (GCompareFunc) strcmp);
211
212           new = g_list_delete_link (new, new);
213         }
214     }
215
216   return out;
217 }
218
219 GList *
220 empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
221                                            TpAccount *account,
222                                            const gchar *chat_id,
223                                            gboolean chatroom,
224                                            const gchar *date)
225 {
226   GList *l, *out = NULL;
227   EmpathyLogManagerPriv *priv;
228
229   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
230   g_return_val_if_fail (chat_id != NULL, NULL);
231
232   priv = GET_PRIV (manager);
233
234   for (l = priv->stores; l; l = g_list_next (l))
235     {
236       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
237
238       out = g_list_concat (out, empathy_log_store_get_messages_for_date (
239           store, account, chat_id, chatroom, date));
240     }
241
242   return out;
243 }
244
245 static gint
246 log_manager_message_date_cmp (gconstpointer a,
247                               gconstpointer b)
248 {
249         EmpathyMessage *one = (EmpathyMessage *) a;
250         EmpathyMessage *two = (EmpathyMessage *) b;
251         time_t one_time, two_time;
252
253         one_time = empathy_message_get_timestamp (one);
254         two_time = empathy_message_get_timestamp (two);
255
256         /* Return -1 of message1 is older than message2 */
257         return one_time < two_time ? -1 : one_time - two_time;
258 }
259
260 GList *
261 empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager,
262                                            TpAccount *account,
263                                            const gchar *chat_id,
264                                            gboolean chatroom,
265                                            guint num_messages,
266                                            EmpathyLogMessageFilter filter,
267                                            gpointer user_data)
268 {
269   EmpathyLogManagerPriv *priv;
270   GList *out = NULL;
271   GList *l;
272   guint i = 0;
273
274   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
275   g_return_val_if_fail (chat_id != NULL, NULL);
276
277   priv = GET_PRIV (manager);
278
279   /* Get num_messages from each log store and keep only the
280    * newest ones in the out list. Keep that list sorted: Older first. */
281   for (l = priv->stores; l; l = g_list_next (l))
282     {
283       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
284       GList *new;
285
286       new = empathy_log_store_get_filtered_messages (store, account, chat_id,
287           chatroom, num_messages, filter, user_data);
288       while (new)
289         {
290           if (i < num_messages)
291             {
292               /* We have less message than needed so far. Keep this message */
293               out = g_list_insert_sorted (out, new->data,
294                   (GCompareFunc) log_manager_message_date_cmp);
295               i++;
296             }
297           else if (log_manager_message_date_cmp (new->data, out->data) > 0)
298             {
299               /* This message is newer than the oldest message we have in out
300                * list. Remove the head of out list and insert this message */
301               g_object_unref (out->data);
302               out = g_list_delete_link (out, out);
303               out = g_list_insert_sorted (out, new->data,
304                   (GCompareFunc) log_manager_message_date_cmp);
305             }
306           else
307             {
308               /* This message is older than the oldest message we have in out
309                * list. Drop it. */
310               g_object_unref (new->data);
311             }
312
313           new = g_list_delete_link (new, new);
314         }
315     }
316
317   return out;
318 }
319
320 GList *
321 empathy_log_manager_get_chats (EmpathyLogManager *manager,
322                                TpAccount *account)
323 {
324   GList *l, *out = NULL;
325   EmpathyLogManagerPriv *priv;
326
327   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
328
329   priv = GET_PRIV (manager);
330
331   for (l = priv->stores; l; l = g_list_next (l))
332     {
333       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
334
335       out = g_list_concat (out,
336           empathy_log_store_get_chats (store, account));
337     }
338
339   return out;
340 }
341
342 GList *
343 empathy_log_manager_search_new (EmpathyLogManager *manager,
344                                 const gchar *text)
345 {
346   GList *l, *out = NULL;
347   EmpathyLogManagerPriv *priv;
348
349   g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
350   g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL);
351
352   priv = GET_PRIV (manager);
353
354   for (l = priv->stores; l; l = g_list_next (l))
355     {
356       EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data);
357
358       out = g_list_concat (out,
359           empathy_log_store_search_new (store, text));
360     }
361
362   return out;
363 }
364
365 void
366 empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit)
367 {
368   if (hit->account != NULL)
369     g_object_unref (hit->account);
370
371   g_free (hit->date);
372   g_free (hit->filename);
373   g_free (hit->chat_id);
374
375   g_slice_free (EmpathyLogSearchHit, hit);
376 }
377
378 void
379 empathy_log_manager_search_free (GList *hits)
380 {
381   GList *l;
382
383   for (l = hits; l; l = g_list_next (l))
384     {
385       empathy_log_manager_search_hit_free (l->data);
386     }
387
388   g_list_free (hits);
389 }
390
391 /* Format is just date, 20061201. */
392 gchar *
393 empathy_log_manager_get_date_readable (const gchar *date)
394 {
395   time_t t;
396
397   t = empathy_time_parse (date);
398
399   return empathy_time_to_string_local (t, "%a %d %b %Y");
400 }
401
402 static void
403 log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat,
404                                       EmpathyMessage *message,
405                                       EmpathyLogManager *log_manager)
406 {
407   GError *error = NULL;
408   TpHandleType handle_type;
409   TpChannel *channel;
410
411   channel = empathy_tp_chat_get_channel (tp_chat);
412   tp_channel_get_handle (channel, &handle_type);
413
414   if (!empathy_log_manager_add_message (log_manager,
415         tp_channel_get_identifier (channel),
416         handle_type == TP_HANDLE_TYPE_ROOM,
417         message, &error))
418     {
419       DEBUG ("Failed to write message: %s",
420           error ? error->message : "No error message");
421
422       if (error != NULL)
423         g_error_free (error);
424     }
425 }
426
427 static void
428 log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher,
429                                    EmpathyDispatchOperation *operation,
430                                    EmpathyLogManager *log_manager)
431 {
432   GQuark channel_type;
433
434   channel_type = empathy_dispatch_operation_get_channel_type_id (operation);
435
436   if (channel_type == TP_IFACE_QUARK_CHANNEL_TYPE_TEXT)
437     {
438       EmpathyTpChat *tp_chat;
439
440       tp_chat = EMPATHY_TP_CHAT (
441           empathy_dispatch_operation_get_channel_wrapper (operation));
442
443       g_signal_connect (tp_chat, "message-received",
444           G_CALLBACK (log_manager_chat_received_message_cb), log_manager);
445     }
446 }
447
448
449 void
450 empathy_log_manager_observe (EmpathyLogManager *log_manager,
451                              EmpathyDispatcher *dispatcher)
452 {
453   g_signal_connect (dispatcher, "observe",
454       G_CALLBACK (log_manager_dispatcher_observe_cb), log_manager);
455 }