]> git.0d.be Git - empathy.git/blob - libempathy/empathy-log-store-empathy.c
Merge commit 'upstream/master' into mc5
[empathy.git] / libempathy / empathy-log-store-empathy.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  *          Jonny Lamb <jonny.lamb@collabora.co.uk>
23  */
24
25 #include <config.h>
26
27 #include <string.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30
31 /* FIXME: g_mapped_file_free has been deprecated in GLib 2.22, but the
32  * replacement symbol, g_mapped_file_unref is not available in older Glib
33  * and we're not ready to bump our version requirement just for this. When
34  * we're ready to bump our version requirement, just revert this patch. */
35 #undef G_DISABLE_DEPRECATED
36 #include <glib/gstdio.h>
37 #define G_DISABLE_DEPRECATED
38
39 #include <telepathy-glib/util.h>
40
41 #include "empathy-log-store.h"
42 #include "empathy-log-store-empathy.h"
43 #include "empathy-log-manager.h"
44 #include "empathy-account-manager.h"
45 #include "empathy-contact.h"
46 #include "empathy-time.h"
47 #include "empathy-utils.h"
48
49 #define DEBUG_FLAG EMPATHY_DEBUG_OTHER
50 #include "empathy-debug.h"
51
52 #define LOG_DIR_CREATE_MODE       (S_IRUSR | S_IWUSR | S_IXUSR)
53 #define LOG_FILE_CREATE_MODE      (S_IRUSR | S_IWUSR)
54 #define LOG_DIR_CHATROOMS         "chatrooms"
55 #define LOG_FILENAME_SUFFIX       ".log"
56 #define LOG_TIME_FORMAT_FULL      "%Y%m%dT%H:%M:%S"
57 #define LOG_TIME_FORMAT           "%Y%m%d"
58 #define LOG_HEADER \
59     "<?xml version='1.0' encoding='utf-8'?>\n" \
60     "<?xml-stylesheet type=\"text/xsl\" href=\"empathy-log.xsl\"?>\n" \
61     "<log>\n"
62
63 #define LOG_FOOTER \
64     "</log>\n"
65
66
67 #define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLogStoreEmpathy)
68 typedef struct
69 {
70   gchar *basedir;
71   gchar *name;
72   EmpathyAccountManager *account_manager;
73 } EmpathyLogStoreEmpathyPriv;
74
75 static void log_store_iface_init (gpointer g_iface,gpointer iface_data);
76
77 G_DEFINE_TYPE_WITH_CODE (EmpathyLogStoreEmpathy, empathy_log_store_empathy,
78     G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (EMPATHY_TYPE_LOG_STORE,
79       log_store_iface_init));
80
81 static void
82 log_store_empathy_finalize (GObject *object)
83 {
84   EmpathyLogStoreEmpathy *self = EMPATHY_LOG_STORE_EMPATHY (object);
85   EmpathyLogStoreEmpathyPriv *priv = GET_PRIV (self);
86
87   g_object_unref (priv->account_manager);
88   g_free (priv->basedir);
89   g_free (priv->name);
90 }
91
92 static void
93 empathy_log_store_empathy_class_init (EmpathyLogStoreEmpathyClass *klass)
94 {
95   GObjectClass *object_class = G_OBJECT_CLASS (klass);
96
97   object_class->finalize = log_store_empathy_finalize;
98
99   g_type_class_add_private (object_class, sizeof (EmpathyLogStoreEmpathyPriv));
100 }
101
102 static void
103 empathy_log_store_empathy_init (EmpathyLogStoreEmpathy *self)
104 {
105   EmpathyLogStoreEmpathyPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
106       EMPATHY_TYPE_LOG_STORE_EMPATHY, EmpathyLogStoreEmpathyPriv);
107
108   self->priv = priv;
109
110   priv->basedir = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (),
111     PACKAGE_NAME, "logs", NULL);
112
113   priv->name = g_strdup ("Empathy");
114   priv->account_manager = empathy_account_manager_dup_singleton ();
115 }
116
117 static gchar *
118 log_store_empathy_get_dir (EmpathyLogStore *self,
119                            EmpathyAccount *account,
120                            const gchar *chat_id,
121                            gboolean chatroom)
122 {
123   gchar *basedir;
124   gchar *escaped;
125   EmpathyLogStoreEmpathyPriv *priv;
126
127   priv = GET_PRIV (self);
128
129   /* unique name is an object path, ignore the initial / and replace the others
130    * by % */
131   escaped = g_strdup (empathy_account_get_unique_name (account) + 1);
132
133   g_strdelimit (escaped, "/", '%');
134
135   if (chatroom)
136     basedir = g_build_path (G_DIR_SEPARATOR_S, priv->basedir, escaped,
137         LOG_DIR_CHATROOMS, chat_id, NULL);
138   else
139     basedir = g_build_path (G_DIR_SEPARATOR_S, priv->basedir,
140         escaped, chat_id, NULL);
141
142   g_free (escaped);
143
144   return basedir;
145 }
146
147 static gchar *
148 log_store_empathy_get_timestamp_filename (void)
149 {
150   time_t t;
151   gchar *time_str;
152   gchar *filename;
153
154   t = empathy_time_get_current ();
155   time_str = empathy_time_to_string_local (t, LOG_TIME_FORMAT);
156   filename = g_strconcat (time_str, LOG_FILENAME_SUFFIX, NULL);
157
158   g_free (time_str);
159
160   return filename;
161 }
162
163 static gchar *
164 log_store_empathy_get_timestamp_from_message (EmpathyMessage *message)
165 {
166   time_t t;
167
168   t = empathy_message_get_timestamp (message);
169
170   /* We keep the timestamps in the messages as UTC. */
171   return empathy_time_to_string_utc (t, LOG_TIME_FORMAT_FULL);
172 }
173
174 static gchar *
175 log_store_empathy_get_filename (EmpathyLogStore *self,
176                                 EmpathyAccount *account,
177                                 const gchar *chat_id,
178                                 gboolean chatroom)
179 {
180   gchar *basedir;
181   gchar *timestamp;
182   gchar *filename;
183
184   basedir = log_store_empathy_get_dir (self, account, chat_id, chatroom);
185   timestamp = log_store_empathy_get_timestamp_filename ();
186   filename = g_build_filename (basedir, timestamp, NULL);
187
188   g_free (basedir);
189   g_free (timestamp);
190
191   return filename;
192 }
193
194 static gboolean
195 log_store_empathy_add_message (EmpathyLogStore *self,
196                                const gchar *chat_id,
197                                gboolean chatroom,
198                                EmpathyMessage *message,
199                                GError **error)
200 {
201   FILE *file;
202   EmpathyAccount *account;
203   EmpathyContact *sender;
204   const gchar *body_str;
205   const gchar *str;
206   EmpathyAvatar *avatar;
207   gchar *avatar_token = NULL;
208   gchar *filename;
209   gchar *basedir;
210   gchar *body;
211   gchar *timestamp;
212   gchar *contact_name;
213   gchar *contact_id;
214   TpChannelTextMessageType msg_type;
215
216   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), FALSE);
217   g_return_val_if_fail (chat_id != NULL, FALSE);
218   g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE);
219
220   sender = empathy_message_get_sender (message);
221   account = empathy_contact_get_account (sender);
222   body_str = empathy_message_get_body (message);
223   msg_type = empathy_message_get_tptype (message);
224
225   if (EMP_STR_EMPTY (body_str))
226     return FALSE;
227
228   filename = log_store_empathy_get_filename (self, account, chat_id, chatroom);
229   basedir = g_path_get_dirname (filename);
230   if (!g_file_test (basedir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR))
231     {
232       DEBUG ("Creating directory:'%s'", basedir);
233       g_mkdir_with_parents (basedir, LOG_DIR_CREATE_MODE);
234     }
235   g_free (basedir);
236
237   DEBUG ("Adding message: '%s' to file: '%s'", body_str, filename);
238
239   if (!g_file_test (filename, G_FILE_TEST_EXISTS))
240     {
241       file = g_fopen (filename, "w+");
242       if (file != NULL)
243         g_fprintf (file, LOG_HEADER);
244
245       g_chmod (filename, LOG_FILE_CREATE_MODE);
246     }
247   else
248     {
249       file = g_fopen (filename, "r+");
250       if (file != NULL)
251         fseek (file, - strlen (LOG_FOOTER), SEEK_END);
252     }
253
254   body = g_markup_escape_text (body_str, -1);
255   timestamp = log_store_empathy_get_timestamp_from_message (message);
256
257   str = empathy_contact_get_name (sender);
258   contact_name = g_markup_escape_text (str, -1);
259
260   str = empathy_contact_get_id (sender);
261   contact_id = g_markup_escape_text (str, -1);
262
263   avatar = empathy_contact_get_avatar (sender);
264   if (avatar != NULL)
265     avatar_token = g_markup_escape_text (avatar->token, -1);
266
267   g_fprintf (file,
268        "<message time='%s' cm_id='%d' id='%s' name='%s' token='%s' isuser='%s' type='%s'>"
269        "%s</message>\n" LOG_FOOTER, timestamp,
270        empathy_message_get_id (message),
271        contact_id, contact_name,
272        avatar_token ? avatar_token : "",
273        empathy_contact_is_user (sender) ? "true" : "false",
274        empathy_message_type_to_str (msg_type), body);
275
276   fclose (file);
277   g_free (filename);
278   g_free (contact_id);
279   g_free (contact_name);
280   g_free (timestamp);
281   g_free (body);
282   g_free (avatar_token);
283
284   return TRUE;
285 }
286
287 static gboolean
288 log_store_empathy_exists (EmpathyLogStore *self,
289                           EmpathyAccount *account,
290                           const gchar *chat_id,
291                           gboolean chatroom)
292 {
293   gchar *dir;
294   gboolean exists;
295
296   dir = log_store_empathy_get_dir (self, account, chat_id, chatroom);
297   exists = g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
298   g_free (dir);
299
300   return exists;
301 }
302
303 static GList *
304 log_store_empathy_get_dates (EmpathyLogStore *self,
305                              EmpathyAccount *account,
306                              const gchar *chat_id,
307                              gboolean chatroom)
308 {
309   GList *dates = NULL;
310   gchar *date;
311   gchar *directory;
312   GDir *dir;
313   const gchar *filename;
314   const gchar *p;
315
316   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), NULL);
317   g_return_val_if_fail (chat_id != NULL, NULL);
318
319   directory = log_store_empathy_get_dir (self, account, chat_id, chatroom);
320   dir = g_dir_open (directory, 0, NULL);
321   if (!dir)
322     {
323       DEBUG ("Could not open directory:'%s'", directory);
324       g_free (directory);
325       return NULL;
326     }
327
328   DEBUG ("Collating a list of dates in:'%s'", directory);
329
330   while ((filename = g_dir_read_name (dir)) != NULL)
331     {
332       if (!g_str_has_suffix (filename, LOG_FILENAME_SUFFIX))
333         continue;
334
335       p = strstr (filename, LOG_FILENAME_SUFFIX);
336       date = g_strndup (filename, p - filename);
337
338       if (!date)
339         continue;
340
341       if (!g_regex_match_simple ("\\d{8}", date, 0, 0))
342         continue;
343
344       dates = g_list_insert_sorted (dates, date, (GCompareFunc) strcmp);
345     }
346
347   g_free (directory);
348   g_dir_close (dir);
349
350   DEBUG ("Parsed %d dates", g_list_length (dates));
351
352   return dates;
353 }
354
355 static gchar *
356 log_store_empathy_get_filename_for_date (EmpathyLogStore *self,
357                                          EmpathyAccount *account,
358                                          const gchar *chat_id,
359                                          gboolean chatroom,
360                                          const gchar *date)
361 {
362   gchar *basedir;
363   gchar *timestamp;
364   gchar *filename;
365
366   basedir = log_store_empathy_get_dir (self, account, chat_id, chatroom);
367   timestamp = g_strconcat (date, LOG_FILENAME_SUFFIX, NULL);
368   filename = g_build_filename (basedir, timestamp, NULL);
369
370   g_free (basedir);
371   g_free (timestamp);
372
373   return filename;
374 }
375
376 static EmpathyLogSearchHit *
377 log_store_empathy_search_hit_new (EmpathyLogStore *self,
378                                   const gchar *filename)
379 {
380   EmpathyLogStoreEmpathyPriv *priv = GET_PRIV (self);
381   EmpathyLogSearchHit *hit;
382   gchar *unescaped;
383   gchar *account_name;
384   const gchar *end;
385   gchar **strv;
386   guint len;
387
388   if (!g_str_has_suffix (filename, LOG_FILENAME_SUFFIX))
389     return NULL;
390
391   strv = g_strsplit (filename, G_DIR_SEPARATOR_S, -1);
392   len = g_strv_length (strv);
393
394   hit = g_slice_new0 (EmpathyLogSearchHit);
395
396   end = strstr (strv[len-1], LOG_FILENAME_SUFFIX);
397   hit->date = g_strndup (strv[len-1], end - strv[len-1]);
398   hit->chat_id = g_strdup (strv[len-2]);
399   hit->is_chatroom = (strcmp (strv[len-3], LOG_DIR_CHATROOMS) == 0);
400
401   if (hit->is_chatroom)
402     account_name = strv[len-4];
403   else
404     account_name = strv[len-3];
405
406   unescaped = g_strdup_printf ("/%s", g_strdelimit (account_name, "%", '/'));
407
408   hit->account = empathy_account_manager_lookup (priv->account_manager,
409     unescaped);
410   hit->filename = g_strdup (filename);
411
412   g_free (unescaped);
413   g_strfreev (strv);
414
415   return hit;
416 }
417
418 static GList *
419 log_store_empathy_get_messages_for_file (EmpathyLogStore *self,
420                                          const gchar *filename)
421 {
422   GList *messages = NULL;
423   xmlParserCtxtPtr ctxt;
424   xmlDocPtr doc;
425   xmlNodePtr log_node;
426   xmlNodePtr node;
427   EmpathyLogSearchHit *hit;
428   EmpathyAccount *account;
429
430   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), NULL);
431   g_return_val_if_fail (filename != NULL, NULL);
432
433   DEBUG ("Attempting to parse filename:'%s'...", filename);
434
435   if (!g_file_test (filename, G_FILE_TEST_EXISTS))
436     {
437       DEBUG ("Filename:'%s' does not exist", filename);
438       return NULL;
439     }
440
441   /* Get the account from the filename */
442   hit = log_store_empathy_search_hit_new (self, filename);
443
444   if (hit->account != NULL)
445     account = g_object_ref (hit->account);
446
447   empathy_log_manager_search_hit_free (hit);
448
449   if (hit->account == NULL)
450     return NULL;
451
452   /* Create parser. */
453   ctxt = xmlNewParserCtxt ();
454
455   /* Parse and validate the file. */
456   doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
457   if (!doc)
458     {
459       g_warning ("Failed to parse file:'%s'", filename);
460       xmlFreeParserCtxt (ctxt);
461       return NULL;
462     }
463
464   /* The root node, presets. */
465   log_node = xmlDocGetRootElement (doc);
466   if (!log_node)
467     {
468       xmlFreeDoc (doc);
469       xmlFreeParserCtxt (ctxt);
470       return NULL;
471     }
472
473   /* Now get the messages. */
474   for (node = log_node->children; node; node = node->next)
475     {
476       EmpathyMessage *message;
477       EmpathyContact *sender;
478       gchar *time;
479       time_t t;
480       gchar *sender_id;
481       gchar *sender_name;
482       gchar *sender_avatar_token;
483       gchar *body;
484       gchar *is_user_str;
485       gboolean is_user = FALSE;
486       gchar *msg_type_str;
487       gchar *cm_id_str;
488       guint cm_id;
489       TpChannelTextMessageType msg_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
490
491       if (strcmp (node->name, "message") != 0)
492         continue;
493
494       body = xmlNodeGetContent (node);
495       time = xmlGetProp (node, "time");
496       sender_id = xmlGetProp (node, "id");
497       sender_name = xmlGetProp (node, "name");
498       sender_avatar_token = xmlGetProp (node, "token");
499       is_user_str = xmlGetProp (node, "isuser");
500       msg_type_str = xmlGetProp (node, "type");
501       cm_id_str = xmlGetProp (node, "cm_id");
502
503       if (is_user_str)
504         is_user = strcmp (is_user_str, "true") == 0;
505
506       if (msg_type_str)
507         msg_type = empathy_message_type_from_str (msg_type_str);
508
509       if (cm_id_str)
510         cm_id = atoi (cm_id_str);
511
512       t = empathy_time_parse (time);
513
514       sender = empathy_contact_new_for_log (account, sender_id, sender_name,
515                                             is_user);
516
517       if (!EMP_STR_EMPTY (sender_avatar_token))
518         empathy_contact_load_avatar_cache (sender,
519             sender_avatar_token);
520
521       message = empathy_message_new (body);
522       empathy_message_set_sender (message, sender);
523       empathy_message_set_timestamp (message, t);
524       empathy_message_set_tptype (message, msg_type);
525       empathy_message_set_is_backlog (message, TRUE);
526
527       if (cm_id_str)
528         empathy_message_set_id (message, cm_id);
529
530       messages = g_list_append (messages, message);
531
532       g_object_unref (sender);
533       xmlFree (time);
534       xmlFree (sender_id);
535       xmlFree (sender_name);
536       xmlFree (body);
537       xmlFree (is_user_str);
538       xmlFree (msg_type_str);
539       xmlFree (cm_id_str);
540       xmlFree (sender_avatar_token);
541     }
542
543   DEBUG ("Parsed %d messages", g_list_length (messages));
544
545   xmlFreeDoc (doc);
546   xmlFreeParserCtxt (ctxt);
547
548   return messages;
549 }
550
551 static GList *
552 log_store_empathy_get_all_files (EmpathyLogStore *self,
553                                  const gchar *dir)
554 {
555   GDir *gdir;
556   GList *files = NULL;
557   const gchar *name;
558   const gchar *basedir;
559   EmpathyLogStoreEmpathyPriv *priv;
560
561   priv = GET_PRIV (self);
562
563   basedir = dir ? dir : priv->basedir;
564
565   gdir = g_dir_open (basedir, 0, NULL);
566   if (!gdir)
567     return NULL;
568
569   while ((name = g_dir_read_name (gdir)) != NULL)
570     {
571       gchar *filename;
572
573       filename = g_build_filename (basedir, name, NULL);
574       if (g_str_has_suffix (filename, LOG_FILENAME_SUFFIX))
575         {
576           files = g_list_prepend (files, filename);
577           continue;
578         }
579
580       if (g_file_test (filename, G_FILE_TEST_IS_DIR))
581         {
582           /* Recursively get all log files */
583           files = g_list_concat (files,
584               log_store_empathy_get_all_files (self, filename));
585         }
586
587       g_free (filename);
588     }
589
590   g_dir_close (gdir);
591
592   return files;
593 }
594
595 static GList *
596 log_store_empathy_search_new (EmpathyLogStore *self,
597                               const gchar *text)
598 {
599   GList *files, *l;
600   GList *hits = NULL;
601   gchar *text_casefold;
602
603   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), NULL);
604   g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL);
605
606   text_casefold = g_utf8_casefold (text, -1);
607
608   files = log_store_empathy_get_all_files (self, NULL);
609   DEBUG ("Found %d log files in total", g_list_length (files));
610
611   for (l = files; l; l = g_list_next (l))
612     {
613       gchar *filename;
614       GMappedFile *file;
615       gsize length;
616       gchar *contents;
617       gchar *contents_casefold;
618
619       filename = l->data;
620
621       file = g_mapped_file_new (filename, FALSE, NULL);
622       if (!file)
623         continue;
624
625       length = g_mapped_file_get_length (file);
626       contents = g_mapped_file_get_contents (file);
627       contents_casefold = g_utf8_casefold (contents, length);
628
629       g_mapped_file_free (file);
630
631       if (strstr (contents_casefold, text_casefold))
632         {
633           EmpathyLogSearchHit *hit;
634
635           hit = log_store_empathy_search_hit_new (self, filename);
636
637           if (hit)
638             {
639               hits = g_list_prepend (hits, hit);
640               DEBUG ("Found text:'%s' in file:'%s' on date:'%s'",
641                   text, hit->filename, hit->date);
642             }
643         }
644
645       g_free (contents_casefold);
646       g_free (filename);
647     }
648
649   g_list_free (files);
650   g_free (text_casefold);
651
652   return hits;
653 }
654
655 static GList *
656 log_store_empathy_get_chats_for_dir (EmpathyLogStore *self,
657                                      const gchar *dir,
658                                      gboolean is_chatroom)
659 {
660   GDir *gdir;
661   GList *hits = NULL;
662   const gchar *name;
663   GError *error = NULL;
664
665   gdir = g_dir_open (dir, 0, &error);
666   if (!gdir)
667     {
668       DEBUG ("Failed to open directory: %s, error: %s", dir, error->message);
669       g_error_free (error);
670       return NULL;
671     }
672
673   while ((name = g_dir_read_name (gdir)) != NULL)
674     {
675       EmpathyLogSearchHit *hit;
676
677       if (!is_chatroom && strcmp (name, LOG_DIR_CHATROOMS) == 0)
678         {
679           gchar *filename = g_build_filename (dir, name, NULL);
680           hits = g_list_concat (hits, log_store_empathy_get_chats_for_dir (
681                 self, filename, TRUE));
682           g_free (filename);
683           continue;
684         }
685       hit = g_slice_new0 (EmpathyLogSearchHit);
686       hit->chat_id = g_strdup (name);
687       hit->is_chatroom = is_chatroom;
688
689       hits = g_list_prepend (hits, hit);
690     }
691
692   g_dir_close (gdir);
693
694   return hits;
695 }
696
697
698 static GList *
699 log_store_empathy_get_messages_for_date (EmpathyLogStore *self,
700                                          EmpathyAccount *account,
701                                          const gchar *chat_id,
702                                          gboolean chatroom,
703                                          const gchar *date)
704 {
705   gchar *filename;
706   GList *messages;
707
708   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), NULL);
709   g_return_val_if_fail (chat_id != NULL, NULL);
710
711   filename = log_store_empathy_get_filename_for_date (self, account,
712       chat_id, chatroom, date);
713   messages = log_store_empathy_get_messages_for_file (self, filename);
714   g_free (filename);
715
716   return messages;
717 }
718
719 static GList *
720 log_store_empathy_get_chats (EmpathyLogStore *self,
721                               EmpathyAccount *account)
722 {
723   gchar *dir;
724   GList *hits;
725   EmpathyLogStoreEmpathyPriv *priv;
726
727   priv = GET_PRIV (self);
728
729   dir = g_build_filename (priv->basedir,
730       empathy_account_get_unique_name (account), NULL);
731
732   hits = log_store_empathy_get_chats_for_dir (self, dir, FALSE);
733
734   g_free (dir);
735
736   return hits;
737 }
738
739 static const gchar *
740 log_store_empathy_get_name (EmpathyLogStore *self)
741 {
742   EmpathyLogStoreEmpathyPriv *priv = GET_PRIV (self);
743
744   return priv->name;
745 }
746
747 static GList *
748 log_store_empathy_get_filtered_messages (EmpathyLogStore *self,
749                                          EmpathyAccount *account,
750                                          const gchar *chat_id,
751                                          gboolean chatroom,
752                                          guint num_messages,
753                                          EmpathyLogMessageFilter filter,
754                                          gpointer user_data)
755 {
756   GList *dates, *l, *messages = NULL;
757   guint i = 0;
758
759   dates = log_store_empathy_get_dates (self, account, chat_id, chatroom);
760
761   for (l = g_list_last (dates); l && i < num_messages; l = g_list_previous (l))
762     {
763       GList *new_messages, *n, *next;
764
765       /* FIXME: We should really restrict the message parsing to get only
766        * the newest num_messages. */
767       new_messages = log_store_empathy_get_messages_for_date (self, account,
768           chat_id, chatroom, l->data);
769
770       n = new_messages;
771       while (n != NULL)
772         {
773           next = g_list_next (n);
774           if (!filter (n->data, user_data))
775             {
776               g_object_unref (n->data);
777               new_messages = g_list_delete_link (new_messages, n);
778             }
779           else
780             {
781               i++;
782             }
783           n = next;
784         }
785       messages = g_list_concat (messages, new_messages);
786     }
787
788   g_list_foreach (dates, (GFunc) g_free, NULL);
789   g_list_free (dates);
790
791   return messages;
792 }
793
794 static void
795 log_store_iface_init (gpointer g_iface,
796                       gpointer iface_data)
797 {
798   EmpathyLogStoreInterface *iface = (EmpathyLogStoreInterface *) g_iface;
799
800   iface->get_name = log_store_empathy_get_name;
801   iface->exists = log_store_empathy_exists;
802   iface->add_message = log_store_empathy_add_message;
803   iface->get_dates = log_store_empathy_get_dates;
804   iface->get_messages_for_date = log_store_empathy_get_messages_for_date;
805   iface->get_chats = log_store_empathy_get_chats;
806   iface->search_new = log_store_empathy_search_new;
807   iface->ack_message = NULL;
808   iface->get_filtered_messages = log_store_empathy_get_filtered_messages;
809 }