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