]> git.0d.be Git - empathy.git/blob - libempathy/empathy-log-manager.c
Rename all filenames starting with "gossip" by "empathy", change namespace
[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) 2007 Collabora Ltd.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public
16  * License along with this program; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  * 
20  * Authors: Xavier Claessens <xclaesse@gmail.com>
21  */
22
23 #include <config.h>
24
25 #include <string.h>
26 #include <stdio.h>
27 #include <glib/gstdio.h>
28
29 #include "empathy-log-manager.h"
30 #include "empathy-contact.h"
31 #include "empathy-time.h"
32 #include "empathy-debug.h"
33 #include "empathy-utils.h"
34
35 #define GET_PRIV(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
36                        EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv))
37
38 #define DEBUG_DOMAIN "LogManager"
39
40 #define LOG_DIR_CREATE_MODE       (S_IRUSR | S_IWUSR | S_IXUSR)
41 #define LOG_FILE_CREATE_MODE      (S_IRUSR | S_IWUSR)
42 #define LOG_DIR_CHATROOMS         "chatrooms"
43 #define LOG_FILENAME_SUFFIX       ".log"
44 #define LOG_TIME_FORMAT_FULL      "%Y%m%dT%H:%M:%S"
45 #define LOG_TIME_FORMAT           "%Y%m%d"
46 #define LOG_HEADER \
47     "<?xml version='1.0' encoding='utf-8'?>\n" \
48     "<?xml-stylesheet type=\"text/xsl\" href=\"empathy-log.xsl\"?>\n" \
49     "<log>\n"
50
51 #define LOG_FOOTER \
52     "</log>\n"
53
54 struct _EmpathyLogManagerPriv {
55         gchar *basedir;
56 };
57
58 static void                 empathy_log_manager_class_init         (EmpathyLogManagerClass *klass);
59 static void                 empathy_log_manager_init               (EmpathyLogManager      *manager);
60 static void                 log_manager_finalize                   (GObject                *object);
61 static const gchar *        log_manager_get_basedir                (EmpathyLogManager      *manager);
62 static GList *              log_manager_get_all_files              (EmpathyLogManager      *manager,
63                                                                     const gchar            *dir);
64 static GList *              log_manager_get_chats                  (EmpathyLogManager      *manager,
65                                                                     const gchar            *dir,
66                                                                     gboolean                is_chatroom);
67 static gchar *              log_manager_get_dir                    (EmpathyLogManager      *manager,
68                                                                     McAccount              *account,
69                                                                     const gchar            *chat_id,
70                                                                     gboolean                chatroom);
71 static gchar *              log_manager_get_filename               (EmpathyLogManager      *manager,
72                                                                     McAccount              *account,
73                                                                     const gchar            *chat_id,
74                                                                     gboolean                chatroom);
75 static gchar *              log_manager_get_filename_for_date      (EmpathyLogManager      *manager,
76                                                                     McAccount              *account,
77                                                                     const gchar            *chat_id,
78                                                                     gboolean                chatroom,
79                                                                     const gchar            *date);
80 static gchar *              log_manager_get_timestamp_filename     (void);
81 static gchar *              log_manager_get_timestamp_from_message (EmpathyMessage          *message);
82 static EmpathyLogSearchHit *log_manager_search_hit_new             (EmpathyLogManager      *manager,
83                                                                     const gchar            *filename);
84
85 G_DEFINE_TYPE (EmpathyLogManager, empathy_log_manager, G_TYPE_OBJECT);
86
87 static void
88 empathy_log_manager_class_init (EmpathyLogManagerClass *klass)
89 {
90         GObjectClass *object_class = G_OBJECT_CLASS (klass);
91
92         object_class->finalize = log_manager_finalize;
93
94         g_type_class_add_private (object_class, sizeof (EmpathyLogManagerPriv));
95 }
96
97 static void
98 empathy_log_manager_init (EmpathyLogManager *manager)
99 {
100 }
101
102 static void
103 log_manager_finalize (GObject *object)
104 {
105         EmpathyLogManagerPriv *priv;
106
107         priv = GET_PRIV (object);
108
109         g_free (priv->basedir);
110 }
111
112 EmpathyLogManager *
113 empathy_log_manager_new (void)
114 {
115         static EmpathyLogManager *manager = NULL;
116
117         if (!manager) {
118                 manager = g_object_new (EMPATHY_TYPE_LOG_MANAGER, NULL);
119                 g_object_add_weak_pointer (G_OBJECT (manager), (gpointer) &manager);
120         } else {
121                 g_object_ref (manager);
122         }
123
124         return manager;
125 }
126
127 void
128 empathy_log_manager_add_message (EmpathyLogManager *manager,
129                                  const gchar       *chat_id,
130                                  gboolean           chatroom,
131                                  EmpathyMessage     *message)
132 {
133         FILE          *file;
134         McAccount     *account;
135         EmpathyContact *sender;
136         const gchar   *body_str;
137         const gchar   *str;
138         gchar         *filename;
139         gchar         *basedir;
140         gchar         *body;
141         gchar         *timestamp;
142         gchar         *contact_name;
143         gchar         *contact_id;
144
145         g_return_if_fail (EMPATHY_IS_LOG_MANAGER (manager));
146         g_return_if_fail (chat_id != NULL);
147         g_return_if_fail (EMPATHY_IS_MESSAGE (message));
148
149         sender = empathy_message_get_sender (message);
150         account = empathy_contact_get_account (sender);
151         body_str = empathy_message_get_body (message);
152
153         if (G_STR_EMPTY (body_str)) {
154                 return;
155         }
156
157         filename = log_manager_get_filename (manager, account, chat_id, chatroom);
158         basedir = g_path_get_dirname (filename);
159         if (!g_file_test (basedir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR)) {
160                 empathy_debug (DEBUG_DOMAIN, "Creating directory:'%s'", basedir);
161
162                 g_mkdir_with_parents (basedir, LOG_DIR_CREATE_MODE);
163         }
164         g_free (basedir);
165
166         empathy_debug (DEBUG_DOMAIN, "Adding message: '%s' to file: '%s'",
167                       body_str, filename);
168
169         if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
170                 file = g_fopen (filename, "w+");
171                 if (file) {
172                         g_fprintf (file, LOG_HEADER);
173                 }
174                 g_chmod (filename, LOG_FILE_CREATE_MODE);
175         } else {
176                 file = g_fopen (filename, "r+");
177                 if (file) {
178                         fseek (file, - strlen (LOG_FOOTER), SEEK_END);
179                 }
180         }
181
182         body = g_markup_escape_text (body_str, -1);
183         timestamp = log_manager_get_timestamp_from_message (message);
184
185         str = empathy_contact_get_name (sender);
186         contact_name = g_markup_escape_text (str, -1);
187
188         str = empathy_contact_get_id (sender);
189         contact_id = g_markup_escape_text (str, -1);
190
191         g_fprintf (file,
192                    "<message time='%s' id='%s' name='%s' isuser='%s'>%s</message>\n" LOG_FOOTER,
193                    timestamp,
194                    contact_id,
195                    contact_name,
196                    empathy_contact_is_user (sender) ? "true" : "false",
197                    body);
198
199         fclose (file);
200         g_free (filename);
201         g_free (contact_id);
202         g_free (contact_name);
203         g_free (timestamp);
204         g_free (body);
205 }
206
207 gboolean
208 empathy_log_manager_exists (EmpathyLogManager *manager,
209                             McAccount         *account,
210                             const gchar       *chat_id,
211                             gboolean           chatroom)
212 {
213         gchar    *dir;
214         gboolean  exists;
215
216         dir = log_manager_get_dir (manager, account, chat_id, chatroom);
217         exists = g_file_test (dir, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_DIR);
218         g_free (dir);
219
220         return exists;
221 }
222
223 GList *
224 empathy_log_manager_get_dates (EmpathyLogManager *manager,
225                                McAccount         *account,
226                                const gchar       *chat_id,
227                                gboolean           chatroom)
228 {
229         GList       *dates = NULL;
230         gchar       *date;
231         gchar       *directory;
232         GDir        *dir;
233         const gchar *filename;
234         const gchar *p;
235
236         g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
237         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
238         g_return_val_if_fail (chat_id != NULL, NULL);
239
240         directory = log_manager_get_dir (manager, account, chat_id, chatroom);
241         dir = g_dir_open (directory, 0, NULL);
242         if (!dir) {
243                 empathy_debug (DEBUG_DOMAIN, "Could not open directory:'%s'", directory);
244                 g_free (directory);
245                 return NULL;
246         }
247
248         empathy_debug (DEBUG_DOMAIN, "Collating a list of dates in:'%s'", directory);
249
250         while ((filename = g_dir_read_name (dir)) != NULL) {
251                 if (!g_str_has_suffix (filename, LOG_FILENAME_SUFFIX)) {
252                         continue;
253                 }
254
255                 p = strstr (filename, LOG_FILENAME_SUFFIX);
256                 date = g_strndup (filename, p - filename);
257                 if (!date) {
258                         continue;
259                 }
260
261                 dates = g_list_insert_sorted (dates, date, (GCompareFunc) strcmp);
262         }
263
264         g_free (directory);
265         g_dir_close (dir);
266
267         empathy_debug (DEBUG_DOMAIN, "Parsed %d dates", g_list_length (dates));
268
269         return dates;
270 }
271
272 GList *
273 empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager,
274                                            McAccount         *account,
275                                            const gchar       *chat_id,
276                                            gboolean           chatroom,
277                                            const gchar       *date)
278 {
279         gchar            *filename;
280         GList            *messages = NULL;
281         xmlParserCtxtPtr  ctxt;
282         xmlDocPtr         doc;
283         xmlNodePtr        log_node;
284         xmlNodePtr        node;
285
286         g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
287         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
288         g_return_val_if_fail (chat_id != NULL, NULL);
289
290         filename = log_manager_get_filename_for_date (manager, account, chat_id, chatroom, date);
291
292         empathy_debug (DEBUG_DOMAIN, "Attempting to parse filename:'%s'...", filename);
293
294         if (!g_file_test (filename, G_FILE_TEST_EXISTS)) {
295                 empathy_debug (DEBUG_DOMAIN, "Filename:'%s' does not exist", filename);
296                 g_free (filename);
297                 return NULL;
298         }
299
300         /* Create parser. */
301         ctxt = xmlNewParserCtxt ();
302
303         /* Parse and validate the file. */
304         doc = xmlCtxtReadFile (ctxt, filename, NULL, 0);
305         if (!doc) {
306                 g_warning ("Failed to parse file:'%s'", filename);
307                 g_free (filename);
308                 xmlFreeParserCtxt (ctxt);
309                 return NULL;
310         }
311
312         /* The root node, presets. */
313         log_node = xmlDocGetRootElement (doc);
314         if (!log_node) {
315                 g_free (filename);
316                 xmlFreeDoc (doc);
317                 xmlFreeParserCtxt (ctxt);
318                 return NULL;
319         }
320
321         /* Now get the messages. */
322         for (node = log_node->children; node; node = node->next) {
323                 EmpathyMessage *message;
324                 EmpathyContact *sender;
325                 gchar         *time;
326                 EmpathyTime     t;
327                 gchar         *sender_id;
328                 gchar         *sender_name;
329                 gchar         *body;
330                 gchar         *is_user_str;
331                 gboolean       is_user = FALSE;
332
333                 if (strcmp (node->name, "message") != 0) {
334                         continue;
335                 }
336
337                 body = xmlNodeGetContent (node);
338                 time = xmlGetProp (node, "time");
339                 sender_id = xmlGetProp (node, "id");
340                 sender_name = xmlGetProp (node, "name");
341                 is_user_str = xmlGetProp (node, "isuser");
342
343                 if (is_user_str) {
344                         is_user = strcmp (is_user_str, "true") == 0;
345                 }
346
347                 t = empathy_time_parse (time);
348
349                 sender = empathy_contact_new_full (account, sender_id, sender_name);
350                 empathy_contact_set_is_user (sender, is_user);
351                 message = empathy_message_new (body);
352                 empathy_message_set_sender (message, sender);
353                 empathy_message_set_timestamp (message, t);
354
355                 messages = g_list_append (messages, message);
356
357                 g_object_unref (sender);
358                 xmlFree (time);
359                 xmlFree (sender_id);
360                 xmlFree (sender_name);
361                 xmlFree (body);
362         }
363
364         empathy_debug (DEBUG_DOMAIN, "Parsed %d messages", g_list_length (messages));
365
366         g_free (filename);
367         xmlFreeDoc (doc);
368         xmlFreeParserCtxt (ctxt);
369
370         return messages;
371 }
372
373 GList *
374 empathy_log_manager_get_last_messages (EmpathyLogManager *manager,
375                                        McAccount         *account,
376                                        const gchar       *chat_id,
377                                        gboolean           chatroom)
378 {
379         GList *messages = NULL;
380         GList *dates;
381         GList *l;
382
383         g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
384         g_return_val_if_fail (MC_IS_ACCOUNT (account), NULL);
385         g_return_val_if_fail (chat_id != NULL, NULL);
386
387         dates = empathy_log_manager_get_dates (manager, account, chat_id, chatroom);
388
389         l = g_list_last (dates);
390         if (l) {
391                 messages = empathy_log_manager_get_messages_for_date (manager,
392                                                                       account,
393                                                                       chat_id,
394                                                                       chatroom,
395                                                                       l->data);
396         }
397
398         g_list_foreach (dates, (GFunc) g_free, NULL);
399         g_list_free (dates);
400
401         return messages;
402 }
403
404 GList *
405 empathy_log_manager_get_chats (EmpathyLogManager *manager,
406                                McAccount         *account)
407 {
408         const gchar *basedir;
409         gchar       *dir;
410
411         basedir = log_manager_get_basedir (manager);
412         dir = g_build_filename (basedir,
413                                 mc_account_get_unique_name (account),
414                                 NULL);
415
416         return log_manager_get_chats (manager, dir, FALSE);
417 }
418
419 GList *
420 empathy_log_manager_search_new (EmpathyLogManager *manager,
421                                 const gchar       *text)
422 {
423         GList *files, *l;
424         GList *hits = NULL;
425         gchar *text_casefold;
426
427         g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL);
428         g_return_val_if_fail (!G_STR_EMPTY (text), NULL);
429
430         text_casefold = g_utf8_casefold (text, -1);
431
432         files = log_manager_get_all_files (manager, NULL);
433         empathy_debug (DEBUG_DOMAIN, "Found %d log files in total",
434                       g_list_length (files));
435
436         for (l = files; l; l = l->next) {
437                 gchar       *filename;
438                 GMappedFile *file;
439                 gsize        length;
440                 gchar       *contents;
441                 gchar       *contents_casefold;
442
443                 filename = l->data;
444
445                 file = g_mapped_file_new (filename, FALSE, NULL);
446                 if (!file) {
447                         continue;
448                 }
449
450                 length = g_mapped_file_get_length (file);
451                 contents = g_mapped_file_get_contents (file);
452                 contents_casefold = g_utf8_casefold (contents, length);
453
454                 g_mapped_file_free (file);
455
456                 if (strstr (contents_casefold, text_casefold)) {
457                         EmpathyLogSearchHit *hit;
458
459                         hit = log_manager_search_hit_new (manager, filename);
460
461                         if (hit) {
462                                 hits = g_list_prepend (hits, hit);
463                                 empathy_debug (DEBUG_DOMAIN, 
464                                               "Found text:'%s' in file:'%s' on date:'%s'...",
465                                               text, hit->filename, hit->date);
466                         }
467                 }
468
469                 g_free (contents_casefold);
470                 g_free (filename);
471         }
472         g_list_free (files);
473
474         g_free (text_casefold);
475
476         return hits;
477 }
478
479 void
480 empathy_log_manager_search_free (GList *hits)
481 {
482         GList               *l;
483         EmpathyLogSearchHit *hit;
484
485         for (l = hits; l; l = l->next) {
486                 hit = l->data;
487
488                 if (hit->account) {
489                         g_object_unref (hit->account);
490                 }
491
492                 g_free (hit->date);
493                 g_free (hit->filename);
494                 g_free (hit->chat_id);
495
496                 g_slice_free (EmpathyLogSearchHit, hit);
497         }
498         
499         g_list_free (hits);
500 }
501
502 /* Format is just date, 20061201. */
503 gchar *
504 empathy_log_manager_get_date_readable (const gchar *date)
505 {
506         EmpathyTime t;
507
508         t = empathy_time_parse (date);
509
510         return empathy_time_to_string_local (t, "%a %d %b %Y");
511 }
512
513 static const gchar *
514 log_manager_get_basedir (EmpathyLogManager *manager)
515 {
516         EmpathyLogManagerPriv *priv;    
517
518         priv = GET_PRIV (manager);
519
520         if (priv->basedir) {
521                 return priv->basedir;
522         }
523
524         priv->basedir = g_build_path (G_DIR_SEPARATOR_S,
525                                       g_get_home_dir (),
526                                       ".gnome2",
527                                       PACKAGE_NAME,
528                                       "logs",
529                                       NULL);
530
531         return priv->basedir;
532 }
533
534 static GList *
535 log_manager_get_all_files (EmpathyLogManager *manager,
536                            const gchar       *dir)
537 {
538         GDir        *gdir;
539         GList       *files = NULL;
540         const gchar *name;
541         
542         if (!dir) {
543                 dir = log_manager_get_basedir (manager);
544         }
545
546         gdir = g_dir_open (dir, 0, NULL);
547         if (!gdir) {
548                 return NULL;
549         }
550
551         while ((name = g_dir_read_name (gdir)) != NULL) {
552                 gchar *filename;
553
554                 filename = g_build_filename (dir, name, NULL);
555                 if (g_str_has_suffix (filename, LOG_FILENAME_SUFFIX)) {
556                         files = g_list_prepend (files, filename);
557                         continue;
558                 }
559
560                 if (g_file_test (filename, G_FILE_TEST_IS_DIR)) {
561                         /* Recursively get all log files */
562                         files = g_list_concat (files, log_manager_get_all_files (manager, filename));
563                 }
564                 g_free (filename);
565         }
566
567         g_dir_close (gdir);
568
569         return files;
570 }
571
572 static GList *
573 log_manager_get_chats (EmpathyLogManager *manager,
574                        const gchar       *dir,
575                        gboolean           is_chatroom)
576 {
577         GDir        *gdir;
578         GList       *hits = NULL;
579         const gchar *name;
580
581         gdir = g_dir_open (dir, 0, NULL);
582         if (!gdir) {
583                 return NULL;
584         }
585
586         while ((name = g_dir_read_name (gdir)) != NULL) {
587                 EmpathyLogSearchHit *hit;
588                 gchar *filename;
589
590                 filename = g_build_filename (dir, name, NULL);
591                 if (strcmp (name, LOG_DIR_CHATROOMS) == 0) {
592                         hits = g_list_concat (hits, log_manager_get_chats (manager, filename, TRUE));
593                         g_free (filename);
594                         continue;
595                 }
596
597                 hit = g_slice_new0 (EmpathyLogSearchHit);
598                 hit->chat_id = g_strdup (name);
599                 hit->is_chatroom = is_chatroom;
600
601                 hits = g_list_prepend (hits, hit);
602         }
603
604         g_dir_close (gdir);
605
606         return hits;
607 }
608
609 static gchar *
610 log_manager_get_dir (EmpathyLogManager *manager,
611                      McAccount         *account,
612                      const gchar       *chat_id,
613                      gboolean           chatroom)
614 {
615         const gchar *account_id;
616         gchar       *basedir;
617         gchar       *str;
618
619         account_id = mc_account_get_unique_name (account);
620         basedir = 
621         str = g_build_path (G_DIR_SEPARATOR_S,
622                             log_manager_get_basedir (manager),
623                             account_id,
624                             chat_id,
625                             NULL);
626
627         if (chatroom) {
628                 basedir = g_build_path (G_DIR_SEPARATOR_S,
629                                         str,
630                                         LOG_DIR_CHATROOMS,
631                                         NULL);
632                 g_free (str);
633         } else {
634                 basedir = str;
635         }
636
637         return basedir;
638 }
639
640 static gchar *
641 log_manager_get_filename (EmpathyLogManager *manager,
642                           McAccount         *account,
643                           const gchar       *chat_id,
644                           gboolean           chatroom)
645 {
646         gchar *basedir;
647         gchar *timestamp;
648         gchar *filename;
649
650         basedir = log_manager_get_dir (manager, account, chat_id, chatroom);
651         timestamp = log_manager_get_timestamp_filename ();
652         filename = g_build_filename (basedir, timestamp, NULL);
653
654         g_free (basedir);
655         g_free (timestamp);
656
657         return filename;
658 }
659
660 static gchar *
661 log_manager_get_filename_for_date (EmpathyLogManager *manager,
662                                    McAccount         *account,
663                                    const gchar       *chat_id,
664                                    gboolean           chatroom,
665                                    const gchar       *date)
666 {
667         gchar *basedir;
668         gchar *timestamp;
669         gchar *filename;
670
671         basedir = log_manager_get_dir (manager, account, chat_id, chatroom);
672         timestamp = g_strconcat (date, LOG_FILENAME_SUFFIX, NULL);
673         filename = g_build_filename (basedir, timestamp, NULL);
674
675         g_free (basedir);
676         g_free (timestamp);
677
678         return filename;
679 }
680
681 static gchar *
682 log_manager_get_timestamp_filename (void)
683 {
684         EmpathyTime  t;
685         gchar      *time_str;
686         gchar      *filename;
687
688         t = empathy_time_get_current ();
689         time_str = empathy_time_to_string_local (t, LOG_TIME_FORMAT);
690         filename = g_strconcat (time_str, LOG_FILENAME_SUFFIX, NULL);
691
692         g_free (time_str);
693
694         return filename;
695 }
696
697 static gchar *
698 log_manager_get_timestamp_from_message (EmpathyMessage *message)
699 {
700         EmpathyTime t;
701
702         t = empathy_message_get_timestamp (message);
703
704         /* We keep the timestamps in the messages as UTC. */
705         return empathy_time_to_string_utc (t, LOG_TIME_FORMAT_FULL);
706 }
707
708 static EmpathyLogSearchHit *
709 log_manager_search_hit_new (EmpathyLogManager *manager,
710                             const gchar       *filename)
711 {
712         EmpathyLogSearchHit  *hit;
713         const gchar          *account_name;
714         const gchar          *end;
715         gchar               **strv;
716         guint                 len;
717
718         if (!g_str_has_suffix (filename, LOG_FILENAME_SUFFIX)) {
719                 return NULL;
720         }
721
722         strv = g_strsplit (filename, G_DIR_SEPARATOR_S, -1);
723         len = g_strv_length (strv);
724
725         hit = g_slice_new0 (EmpathyLogSearchHit);
726
727         end = strstr (strv[len-1], LOG_FILENAME_SUFFIX);
728         hit->date = g_strndup (strv[len-1], end - strv[len-1]);
729         hit->chat_id = g_strdup (strv[len-2]);
730         hit->is_chatroom = (strcmp (strv[len-3], LOG_DIR_CHATROOMS) == 0);
731         if (hit->is_chatroom) {
732                 account_name = strv[len-4];
733         } else {
734                 account_name = strv[len-3];
735         }
736         hit->account = mc_account_lookup (account_name);
737         hit->filename = g_strdup (filename);
738
739         g_strfreev (strv);
740
741         return hit;
742 }
743