]> git.0d.be Git - empathy.git/blob - libempathy/empathy-log-store-empathy.c
Add a new DEBUG domain for the mc4 account importer
[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_get_account (priv->account_manager,
409     unescaped);
410   if (hit->account != NULL)
411     g_object_ref (hit->account);
412   hit->filename = g_strdup (filename);
413
414   g_free (unescaped);
415   g_strfreev (strv);
416
417   return hit;
418 }
419
420 static GList *
421 log_store_empathy_get_messages_for_file (EmpathyLogStore *self,
422                                          const gchar *filename)
423 {
424   GList *messages = NULL;
425   xmlParserCtxtPtr ctxt;
426   xmlDocPtr doc;
427   xmlNodePtr log_node;
428   xmlNodePtr node;
429   EmpathyLogSearchHit *hit;
430   EmpathyAccount *account;
431
432   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), NULL);
433   g_return_val_if_fail (filename != NULL, NULL);
434
435   DEBUG ("Attempting to parse filename:'%s'...", filename);
436
437   if (!g_file_test (filename, G_FILE_TEST_EXISTS))
438     {
439       DEBUG ("Filename:'%s' does not exist", filename);
440       return NULL;
441     }
442
443   /* Get the account from the filename */
444   hit = log_store_empathy_search_hit_new (self, filename);
445
446   if (hit->account != NULL)
447     account = g_object_ref (hit->account);
448
449   empathy_log_manager_search_hit_free (hit);
450
451   if (hit->account == NULL)
452     return NULL;
453
454   /* Create parser. */
455   ctxt = xmlNewParserCtxt ();
456
457   /* Parse and validate the file. */
458   doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
459   if (!doc)
460     {
461       g_warning ("Failed to parse file:'%s'", filename);
462       xmlFreeParserCtxt (ctxt);
463       return NULL;
464     }
465
466   /* The root node, presets. */
467   log_node = xmlDocGetRootElement (doc);
468   if (!log_node)
469     {
470       xmlFreeDoc (doc);
471       xmlFreeParserCtxt (ctxt);
472       return NULL;
473     }
474
475   /* Now get the messages. */
476   for (node = log_node->children; node; node = node->next)
477     {
478       EmpathyMessage *message;
479       EmpathyContact *sender;
480       gchar *time;
481       time_t t;
482       gchar *sender_id;
483       gchar *sender_name;
484       gchar *sender_avatar_token;
485       gchar *body;
486       gchar *is_user_str;
487       gboolean is_user = FALSE;
488       gchar *msg_type_str;
489       gchar *cm_id_str;
490       guint cm_id;
491       TpChannelTextMessageType msg_type = TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL;
492
493       if (strcmp (node->name, "message") != 0)
494         continue;
495
496       body = xmlNodeGetContent (node);
497       time = xmlGetProp (node, "time");
498       sender_id = xmlGetProp (node, "id");
499       sender_name = xmlGetProp (node, "name");
500       sender_avatar_token = xmlGetProp (node, "token");
501       is_user_str = xmlGetProp (node, "isuser");
502       msg_type_str = xmlGetProp (node, "type");
503       cm_id_str = xmlGetProp (node, "cm_id");
504
505       if (is_user_str)
506         is_user = strcmp (is_user_str, "true") == 0;
507
508       if (msg_type_str)
509         msg_type = empathy_message_type_from_str (msg_type_str);
510
511       if (cm_id_str)
512         cm_id = atoi (cm_id_str);
513
514       t = empathy_time_parse (time);
515
516       sender = empathy_contact_new_for_log (account, sender_id, sender_name,
517                                             is_user);
518
519       if (!EMP_STR_EMPTY (sender_avatar_token))
520         empathy_contact_load_avatar_cache (sender,
521             sender_avatar_token);
522
523       message = empathy_message_new (body);
524       empathy_message_set_sender (message, sender);
525       empathy_message_set_timestamp (message, t);
526       empathy_message_set_tptype (message, msg_type);
527       empathy_message_set_is_backlog (message, TRUE);
528
529       if (cm_id_str)
530         empathy_message_set_id (message, cm_id);
531
532       messages = g_list_append (messages, message);
533
534       g_object_unref (sender);
535       xmlFree (time);
536       xmlFree (sender_id);
537       xmlFree (sender_name);
538       xmlFree (body);
539       xmlFree (is_user_str);
540       xmlFree (msg_type_str);
541       xmlFree (cm_id_str);
542       xmlFree (sender_avatar_token);
543     }
544
545   DEBUG ("Parsed %d messages", g_list_length (messages));
546
547   xmlFreeDoc (doc);
548   xmlFreeParserCtxt (ctxt);
549
550   return messages;
551 }
552
553 static GList *
554 log_store_empathy_get_all_files (EmpathyLogStore *self,
555                                  const gchar *dir)
556 {
557   GDir *gdir;
558   GList *files = NULL;
559   const gchar *name;
560   const gchar *basedir;
561   EmpathyLogStoreEmpathyPriv *priv;
562
563   priv = GET_PRIV (self);
564
565   basedir = dir ? dir : priv->basedir;
566
567   gdir = g_dir_open (basedir, 0, NULL);
568   if (!gdir)
569     return NULL;
570
571   while ((name = g_dir_read_name (gdir)) != NULL)
572     {
573       gchar *filename;
574
575       filename = g_build_filename (basedir, name, NULL);
576       if (g_str_has_suffix (filename, LOG_FILENAME_SUFFIX))
577         {
578           files = g_list_prepend (files, filename);
579           continue;
580         }
581
582       if (g_file_test (filename, G_FILE_TEST_IS_DIR))
583         {
584           /* Recursively get all log files */
585           files = g_list_concat (files,
586               log_store_empathy_get_all_files (self, filename));
587         }
588
589       g_free (filename);
590     }
591
592   g_dir_close (gdir);
593
594   return files;
595 }
596
597 static GList *
598 log_store_empathy_search_new (EmpathyLogStore *self,
599                               const gchar *text)
600 {
601   GList *files, *l;
602   GList *hits = NULL;
603   gchar *text_casefold;
604
605   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), NULL);
606   g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL);
607
608   text_casefold = g_utf8_casefold (text, -1);
609
610   files = log_store_empathy_get_all_files (self, NULL);
611   DEBUG ("Found %d log files in total", g_list_length (files));
612
613   for (l = files; l; l = g_list_next (l))
614     {
615       gchar *filename;
616       GMappedFile *file;
617       gsize length;
618       gchar *contents;
619       gchar *contents_casefold;
620
621       filename = l->data;
622
623       file = g_mapped_file_new (filename, FALSE, NULL);
624       if (!file)
625         continue;
626
627       length = g_mapped_file_get_length (file);
628       contents = g_mapped_file_get_contents (file);
629       contents_casefold = g_utf8_casefold (contents, length);
630
631       g_mapped_file_free (file);
632
633       if (strstr (contents_casefold, text_casefold))
634         {
635           EmpathyLogSearchHit *hit;
636
637           hit = log_store_empathy_search_hit_new (self, filename);
638
639           if (hit)
640             {
641               hits = g_list_prepend (hits, hit);
642               DEBUG ("Found text:'%s' in file:'%s' on date:'%s'",
643                   text, hit->filename, hit->date);
644             }
645         }
646
647       g_free (contents_casefold);
648       g_free (filename);
649     }
650
651   g_list_free (files);
652   g_free (text_casefold);
653
654   return hits;
655 }
656
657 static GList *
658 log_store_empathy_get_chats_for_dir (EmpathyLogStore *self,
659                                      const gchar *dir,
660                                      gboolean is_chatroom)
661 {
662   GDir *gdir;
663   GList *hits = NULL;
664   const gchar *name;
665   GError *error = NULL;
666
667   gdir = g_dir_open (dir, 0, &error);
668   if (!gdir)
669     {
670       DEBUG ("Failed to open directory: %s, error: %s", dir, error->message);
671       g_error_free (error);
672       return NULL;
673     }
674
675   while ((name = g_dir_read_name (gdir)) != NULL)
676     {
677       EmpathyLogSearchHit *hit;
678
679       if (!is_chatroom && strcmp (name, LOG_DIR_CHATROOMS) == 0)
680         {
681           gchar *filename = g_build_filename (dir, name, NULL);
682           hits = g_list_concat (hits, log_store_empathy_get_chats_for_dir (
683                 self, filename, TRUE));
684           g_free (filename);
685           continue;
686         }
687       hit = g_slice_new0 (EmpathyLogSearchHit);
688       hit->chat_id = g_strdup (name);
689       hit->is_chatroom = is_chatroom;
690
691       hits = g_list_prepend (hits, hit);
692     }
693
694   g_dir_close (gdir);
695
696   return hits;
697 }
698
699
700 static GList *
701 log_store_empathy_get_messages_for_date (EmpathyLogStore *self,
702                                          EmpathyAccount *account,
703                                          const gchar *chat_id,
704                                          gboolean chatroom,
705                                          const gchar *date)
706 {
707   gchar *filename;
708   GList *messages;
709
710   g_return_val_if_fail (EMPATHY_IS_LOG_STORE (self), NULL);
711   g_return_val_if_fail (chat_id != NULL, NULL);
712
713   filename = log_store_empathy_get_filename_for_date (self, account,
714       chat_id, chatroom, date);
715   messages = log_store_empathy_get_messages_for_file (self, filename);
716   g_free (filename);
717
718   return messages;
719 }
720
721 static GList *
722 log_store_empathy_get_chats (EmpathyLogStore *self,
723                               EmpathyAccount *account)
724 {
725   gchar *dir;
726   GList *hits;
727   EmpathyLogStoreEmpathyPriv *priv;
728
729   priv = GET_PRIV (self);
730
731   dir = g_build_filename (priv->basedir,
732       empathy_account_get_unique_name (account), NULL);
733
734   hits = log_store_empathy_get_chats_for_dir (self, dir, FALSE);
735
736   g_free (dir);
737
738   return hits;
739 }
740
741 static const gchar *
742 log_store_empathy_get_name (EmpathyLogStore *self)
743 {
744   EmpathyLogStoreEmpathyPriv *priv = GET_PRIV (self);
745
746   return priv->name;
747 }
748
749 static GList *
750 log_store_empathy_get_filtered_messages (EmpathyLogStore *self,
751                                          EmpathyAccount *account,
752                                          const gchar *chat_id,
753                                          gboolean chatroom,
754                                          guint num_messages,
755                                          EmpathyLogMessageFilter filter,
756                                          gpointer user_data)
757 {
758   GList *dates, *l, *messages = NULL;
759   guint i = 0;
760
761   dates = log_store_empathy_get_dates (self, account, chat_id, chatroom);
762
763   for (l = g_list_last (dates); l && i < num_messages; l = g_list_previous (l))
764     {
765       GList *new_messages, *n, *next;
766
767       /* FIXME: We should really restrict the message parsing to get only
768        * the newest num_messages. */
769       new_messages = log_store_empathy_get_messages_for_date (self, account,
770           chat_id, chatroom, l->data);
771
772       n = new_messages;
773       while (n != NULL)
774         {
775           next = g_list_next (n);
776           if (!filter (n->data, user_data))
777             {
778               g_object_unref (n->data);
779               new_messages = g_list_delete_link (new_messages, n);
780             }
781           else
782             {
783               i++;
784             }
785           n = next;
786         }
787       messages = g_list_concat (messages, new_messages);
788     }
789
790   g_list_foreach (dates, (GFunc) g_free, NULL);
791   g_list_free (dates);
792
793   return messages;
794 }
795
796 static void
797 log_store_iface_init (gpointer g_iface,
798                       gpointer iface_data)
799 {
800   EmpathyLogStoreInterface *iface = (EmpathyLogStoreInterface *) g_iface;
801
802   iface->get_name = log_store_empathy_get_name;
803   iface->exists = log_store_empathy_exists;
804   iface->add_message = log_store_empathy_add_message;
805   iface->get_dates = log_store_empathy_get_dates;
806   iface->get_messages_for_date = log_store_empathy_get_messages_for_date;
807   iface->get_chats = log_store_empathy_get_chats;
808   iface->search_new = log_store_empathy_search_new;
809   iface->ack_message = NULL;
810   iface->get_filtered_messages = log_store_empathy_get_filtered_messages;
811 }