Fix FSF address (Tobias Mueller, #470445)
[platform/upstream/evolution-data-server.git] / camel / providers / local / camel-local-folder.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  *  Authors: Michael Zucchi <notzed@ximian.com>
4  *
5  *  Copyright 1999-2003 Ximian, Inc. (www.ximian.com)
6  *
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <errno.h>
28 #include <fcntl.h>
29 #include <limits.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <sys/stat.h>
34 #include <sys/types.h>
35
36 #include <glib.h>
37 #include <glib/gi18n-lib.h>
38 #include <glib/gstdio.h>
39
40 #if !defined (G_OS_WIN32) && !defined (_POSIX_PATH_MAX)
41 #include <posix1_lim.h>
42 #endif
43
44 #include "camel-data-wrapper.h"
45 #include "camel-exception.h"
46 #include "camel-mime-filter-from.h"
47 #include "camel-mime-message.h"
48 #include "camel-private.h"
49 #include "camel-stream-filter.h"
50 #include "camel-stream-fs.h"
51 #include "camel-text-index.h"
52
53 #include "camel-local-folder.h"
54 #include "camel-local-private.h"
55 #include "camel-local-store.h"
56 #include "camel-local-summary.h"
57
58 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
59
60 #ifndef PATH_MAX
61 #define PATH_MAX _POSIX_PATH_MAX
62 #endif
63
64 static CamelFolderClass *parent_class;
65 static GSList *local_folder_properties;
66
67 /* Returns the class for a CamelLocalFolder */
68 #define CLOCALF_CLASS(so) CAMEL_LOCAL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
69 #define CF_CLASS(so) CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(so))
70 #define CLOCALS_CLASS(so) CAMEL_STORE_CLASS (CAMEL_OBJECT_GET_CLASS(so))
71
72 static int local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args);
73 static int local_setv(CamelObject *object, CamelException *ex, CamelArgV *args);
74
75 static int local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex);
76 static void local_unlock(CamelLocalFolder *lf);
77
78 static void local_refresh_info(CamelFolder *folder, CamelException *ex);
79
80 static void local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex);
81 static void local_expunge(CamelFolder *folder, CamelException *ex);
82
83 static GPtrArray *local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex);
84 static GPtrArray *local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex);
85 static void local_search_free(CamelFolder *folder, GPtrArray * result);
86
87 static void local_delete(CamelFolder *folder);
88 static void local_rename(CamelFolder *folder, const char *newname);
89
90 static void local_finalize(CamelObject * object);
91
92 static void
93 camel_local_folder_class_init(CamelLocalFolderClass * camel_local_folder_class)
94 {
95         CamelFolderClass *camel_folder_class = CAMEL_FOLDER_CLASS(camel_local_folder_class);
96         CamelObjectClass *oklass = (CamelObjectClass *)camel_local_folder_class;
97
98         /* virtual method definition */
99
100         /* virtual method overload */
101         oklass->getv = local_getv;
102         oklass->setv = local_setv;
103
104         camel_folder_class->refresh_info = local_refresh_info;
105         camel_folder_class->sync = local_sync;
106         camel_folder_class->expunge = local_expunge;
107
108         camel_folder_class->search_by_expression = local_search_by_expression;
109         camel_folder_class->search_by_uids = local_search_by_uids;
110         camel_folder_class->search_free = local_search_free;
111
112         camel_folder_class->delete = local_delete;
113         camel_folder_class->rename = local_rename;
114
115         camel_local_folder_class->lock = local_lock;
116         camel_local_folder_class->unlock = local_unlock;
117 }
118
119 static void
120 local_init(gpointer object, gpointer klass)
121 {
122         CamelFolder *folder = object;
123         CamelLocalFolder *local_folder = object;
124
125         folder->folder_flags |= (CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY |
126                                  CAMEL_FOLDER_HAS_SEARCH_CAPABILITY);
127
128         folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
129             CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT |
130             CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN |
131             CAMEL_MESSAGE_ANSWERED_ALL | CAMEL_MESSAGE_USER;
132
133         folder->summary = NULL;
134         local_folder->search = NULL;
135
136         local_folder->priv = g_malloc0(sizeof(*local_folder->priv));
137         local_folder->priv->search_lock = g_mutex_new();
138 }
139
140 static void
141 local_finalize(CamelObject * object)
142 {
143         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(object);
144         CamelFolder *folder = (CamelFolder *)object;
145
146         if (folder->summary) {
147                 camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, local_folder->changes, NULL);
148                 camel_object_unref((CamelObject *)folder->summary);
149                 folder->summary = NULL;
150         }
151
152         if (local_folder->search) {
153                 camel_object_unref((CamelObject *)local_folder->search);
154         }
155
156         if (local_folder->index)
157                 camel_object_unref((CamelObject *)local_folder->index);
158
159         while (local_folder->locked> 0)
160                 camel_local_folder_unlock(local_folder);
161
162         g_free(local_folder->base_path);
163         g_free(local_folder->folder_path);
164         g_free(local_folder->summary_path);
165         g_free(local_folder->index_path);
166
167         camel_folder_change_info_free(local_folder->changes);
168         
169         g_mutex_free(local_folder->priv->search_lock);
170         
171         g_free(local_folder->priv);
172 }
173
174 static CamelProperty local_property_list[] = {
175         { CAMEL_LOCAL_FOLDER_INDEX_BODY, "index_body", N_("Index message body data") },
176 };
177
178 CamelType
179 camel_local_folder_get_type(void)
180 {
181         static CamelType camel_local_folder_type = CAMEL_INVALID_TYPE;
182
183         if (camel_local_folder_type == CAMEL_INVALID_TYPE) {
184                 int i;
185
186                 parent_class = (CamelFolderClass *)camel_folder_get_type();
187                 camel_local_folder_type = camel_type_register(camel_folder_get_type(), "CamelLocalFolder",
188                                                              sizeof(CamelLocalFolder),
189                                                              sizeof(CamelLocalFolderClass),
190                                                              (CamelObjectClassInitFunc) camel_local_folder_class_init,
191                                                              NULL,
192                                                              (CamelObjectInitFunc) local_init,
193                                                              (CamelObjectFinalizeFunc) local_finalize);
194
195                 for (i=0;i<sizeof(local_property_list)/sizeof(local_property_list[0]);i++) {
196                         local_property_list[i].description = _(local_property_list[i].description);
197                         local_folder_properties = g_slist_prepend(local_folder_properties, &local_property_list[i]);
198                 }
199         }
200
201         return camel_local_folder_type;
202 }
203
204 CamelLocalFolder *
205 camel_local_folder_construct(CamelLocalFolder *lf, CamelStore *parent_store, const char *full_name, guint32 flags, CamelException *ex)
206 {
207         CamelFolderInfo *fi;
208         CamelFolder *folder;
209         const char *root_dir_path;
210         char *name;
211         char *tmp, *statepath;
212 #ifndef G_OS_WIN32
213         char folder_path[PATH_MAX];
214         struct stat st;
215 #endif
216         int forceindex, len;
217         CamelURL *url;
218         CamelLocalStore *ls = (CamelLocalStore *)parent_store;
219         
220         folder = (CamelFolder *)lf;
221
222         name = g_path_get_basename(full_name);
223
224         camel_folder_construct(folder, parent_store, full_name, name);
225
226         root_dir_path = camel_local_store_get_toplevel_dir(ls);
227         /* strip the trailing '/' which is always present */
228         len = strlen (root_dir_path);
229         tmp = g_alloca (len + 1);
230         strcpy (tmp, root_dir_path);
231         if (len>1 && G_IS_DIR_SEPARATOR(tmp[len-1]))
232                 tmp[len-1] = 0;
233
234         lf->base_path = g_strdup(root_dir_path);
235
236         lf->folder_path = camel_local_store_get_full_path(ls, full_name);
237         lf->summary_path = camel_local_store_get_meta_path(ls, full_name, ".ev-summary");
238         lf->index_path = camel_local_store_get_meta_path(ls, full_name, ".ibex");
239         statepath = camel_local_store_get_meta_path(ls, full_name, ".cmeta");
240
241         camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, statepath, NULL);
242         g_free(statepath);
243
244         lf->flags = flags;
245
246         if (camel_object_state_read(lf) == -1) {
247                 /* No metadata - load defaults and persitify */
248                 camel_object_set(lf, NULL, CAMEL_LOCAL_FOLDER_INDEX_BODY, TRUE, 0);
249                 camel_object_state_write(lf);
250         }
251 #ifndef G_OS_WIN32
252         /* follow any symlinks to the mailbox */
253         if (lstat (lf->folder_path, &st) != -1 && S_ISLNK (st.st_mode) &&
254             realpath (lf->folder_path, folder_path) != NULL) {
255                 g_free (lf->folder_path);
256                 lf->folder_path = g_strdup (folder_path);
257         }
258 #endif
259         lf->changes = camel_folder_change_info_new();
260
261         /* TODO: Remove the following line, it is a temporary workaround to remove
262            the old-format 'ibex' files that might be lying around */
263         g_unlink(lf->index_path);
264
265         /* FIXME: Need to run indexing off of the setv method */
266
267         /* if we have no/invalid index file, force it */
268         forceindex = camel_text_index_check(lf->index_path) == -1;
269         if (lf->flags & CAMEL_STORE_FOLDER_BODY_INDEX) {
270                 int flag = O_RDWR|O_CREAT;
271
272                 if (forceindex)
273                         flag |= O_TRUNC;
274
275                 lf->index = (CamelIndex *)camel_text_index_new(lf->index_path, flag);
276                 if (lf->index == NULL) {
277                         /* yes, this isn't fatal at all */
278                         g_warning("Could not open/create index file: %s: indexing not performed", strerror (errno));
279                         forceindex = FALSE;
280                         /* record that we dont have an index afterall */
281                         lf->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
282                 }
283         } else {
284                 /* if we do have an index file, remove it (?) */
285                 if (forceindex == FALSE)
286                         camel_text_index_remove(lf->index_path);
287                 forceindex = FALSE;
288         }
289
290         folder->summary = (CamelFolderSummary *)CLOCALF_CLASS(lf)->create_summary(lf, lf->summary_path, lf->folder_path, lf->index);
291         if (camel_local_summary_load((CamelLocalSummary *)folder->summary, forceindex, NULL) == -1) {
292                 /* ? */
293         }
294
295         /* We don't need to sync here ..., it can sync later on when it calls refresh info */
296 #if 0
297         /*if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1) {*/
298         /* we sync here so that any hard work setting up the folder isn't lost */
299         /*if (camel_local_summary_sync((CamelLocalSummary *)folder->summary, FALSE, lf->changes, ex) == -1) {
300                 camel_object_unref (CAMEL_OBJECT (folder));
301                 g_free(name);
302                 return NULL;
303                 }*/
304 #endif
305
306         /* TODO: This probably shouldn't be here? */
307         if ((flags & CAMEL_STORE_FOLDER_CREATE) != 0) {
308                 url = camel_url_copy (((CamelService *) parent_store)->url);
309                 camel_url_set_fragment (url, full_name);
310         
311                 fi = g_new0 (CamelFolderInfo, 1);
312                 fi->full_name = g_strdup (full_name);
313                 fi->name = g_strdup (name);
314                 fi->uri = camel_url_to_string (url, 0);
315                 fi->unread = camel_folder_get_unread_message_count(folder);
316                 fi->flags = CAMEL_FOLDER_NOCHILDREN;
317         
318                 camel_url_free (url);
319         
320                 camel_object_trigger_event(CAMEL_OBJECT (parent_store), "folder_created", fi);
321                 camel_folder_info_free(fi);
322         }
323         g_free(name);
324         return lf;
325 }
326
327 /* lock the folder, may be called repeatedly (with matching unlock calls),
328    with type the same or less than the first call */
329 int camel_local_folder_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex)
330 {
331         if (lf->locked > 0) {
332                 /* lets be anal here - its important the code knows what its doing */
333                 g_assert(lf->locktype == type || lf->locktype == CAMEL_LOCK_WRITE);
334         } else {
335                 if (CLOCALF_CLASS(lf)->lock(lf, type, ex) == -1)
336                         return -1;
337                 lf->locktype = type;
338         }
339
340         lf->locked++;
341
342         return 0;
343 }
344
345 /* unlock folder */
346 int camel_local_folder_unlock(CamelLocalFolder *lf)
347 {
348         g_assert(lf->locked>0);
349         lf->locked--;
350         if (lf->locked == 0)
351                 CLOCALF_CLASS(lf)->unlock(lf);
352
353         return 0;
354 }
355
356 static int
357 local_getv(CamelObject *object, CamelException *ex, CamelArgGetV *args)
358 {
359         CamelFolder *folder = (CamelFolder *)object;
360         int i;
361         guint32 tag;
362
363         for (i=0;i<args->argc;i++) {
364                 CamelArgGet *arg = &args->argv[i];
365
366                 tag = arg->tag;
367
368                 switch (tag & CAMEL_ARG_TAG) {
369                 case CAMEL_OBJECT_ARG_DESCRIPTION:
370                         if (folder->description == NULL) {
371                                 char *tmp, *path;
372
373                                 /* check some common prefixes to shorten the name */
374                                 tmp = ((CamelService *)folder->parent_store)->url->path;
375                                 if (tmp == NULL)
376                                         goto skip;
377
378                                 path = g_alloca (strlen (tmp) + strlen (folder->full_name) + 1);
379                                 sprintf (path, "%s/%s", tmp, folder->full_name);
380
381                                 if ((tmp = getenv("HOME")) && strncmp(tmp, path, strlen(tmp)) == 0)
382                                         /* $HOME relative path + protocol string */
383                                         folder->description = g_strdup_printf(_("~%s (%s)"), path+strlen(tmp),
384                                                                               ((CamelService *)folder->parent_store)->url->protocol);
385                                 else if ((tmp = "/var/spool/mail") && strncmp(tmp, path, strlen(tmp)) == 0)
386                                         /* /var/spool/mail relative path + protocol */
387                                         folder->description = g_strdup_printf(_("mailbox:%s (%s)"), path+strlen(tmp),
388                                                                               ((CamelService *)folder->parent_store)->url->protocol);
389                                 else if ((tmp = "/var/mail") && strncmp(tmp, path, strlen(tmp)) == 0)
390                                         folder->description = g_strdup_printf(_("mailbox:%s (%s)"), path+strlen(tmp),
391                                                                               ((CamelService *)folder->parent_store)->url->protocol);
392                                 else
393                                         /* a full path + protocol */
394                                         folder->description = g_strdup_printf(_("%s (%s)"), path, 
395                                                                               ((CamelService *)folder->parent_store)->url->protocol);
396                         }
397                         *arg->ca_str = folder->description;
398                         break;
399
400                 case CAMEL_OBJECT_ARG_PERSISTENT_PROPERTIES:
401                 case CAMEL_FOLDER_ARG_PROPERTIES: {
402                         CamelArgGetV props;
403
404                         props.argc = 1;
405                         props.argv[0] = *arg;
406                         ((CamelObjectClass *)parent_class)->getv(object, ex, &props);
407                         *arg->ca_ptr = g_slist_concat(*arg->ca_ptr, g_slist_copy(local_folder_properties));
408
409                         break; }
410
411                 case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY:
412                         /* FIXME: remove this from sotre flags */
413                         *arg->ca_int = (((CamelLocalFolder *)folder)->flags & CAMEL_STORE_FOLDER_BODY_INDEX) != 0;
414                         break;
415
416                 default: skip:
417                         continue;
418                 }
419
420                 arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
421         }
422
423         return ((CamelObjectClass *)parent_class)->getv(object, ex, args);
424 }
425
426 static int
427 local_setv(CamelObject *object, CamelException *ex, CamelArgV *args)
428 {
429         int i;
430         guint32 tag;
431
432         for (i=0;i<args->argc;i++) {
433                 CamelArg *arg = &args->argv[i];
434
435                 tag = arg->tag;
436
437                 switch (tag & CAMEL_ARG_TAG) {
438                 case CAMEL_LOCAL_FOLDER_ARG_INDEX_BODY:
439                         /* FIXME: implement */
440                         /* TODO: When turning on (off?) the index, we want to launch a task for it,
441                            and make sure we dont have multiple tasks doing the same job */
442                         if (arg->ca_int)
443                                 ((CamelLocalFolder *)object)->flags |= CAMEL_STORE_FOLDER_BODY_INDEX;
444                         else
445                                 ((CamelLocalFolder *)object)->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
446                         break;
447                 default:
448                         continue;
449                 }
450
451                 arg->tag = (tag & CAMEL_ARG_TYPE) | CAMEL_ARG_IGNORE;
452         }
453
454         return ((CamelObjectClass *)parent_class)->setv(object, ex, args);
455 }
456
457 static int
458 local_lock(CamelLocalFolder *lf, CamelLockType type, CamelException *ex)
459 {
460         return 0;
461 }
462
463 static void
464 local_unlock(CamelLocalFolder *lf)
465 {
466         /* nothing */
467 }
468
469 /* for auto-check to work */
470 static void
471 local_refresh_info(CamelFolder *folder, CamelException *ex)
472 {
473         CamelLocalFolder *lf = (CamelLocalFolder *)folder;
474
475         if (camel_local_summary_check((CamelLocalSummary *)folder->summary, lf->changes, ex) == -1)
476                 return;
477
478         if (camel_folder_change_info_changed(lf->changes)) {
479                 camel_object_trigger_event((CamelObject *)folder, "folder_changed", lf->changes);
480                 camel_folder_change_info_clear(lf->changes);
481         }
482 }
483
484 static void
485 local_sync(CamelFolder *folder, gboolean expunge, CamelException *ex)
486 {
487         CamelLocalFolder *lf = CAMEL_LOCAL_FOLDER(folder);
488
489         d(printf("local sync '%s' , expunge=%s\n", folder->full_name, expunge?"true":"false"));
490
491         if (camel_local_folder_lock(lf, CAMEL_LOCK_WRITE, ex) == -1)
492                 return;
493
494         camel_object_state_write(lf);
495
496         /* if sync fails, we'll pass it up on exit through ex */
497         camel_local_summary_sync((CamelLocalSummary *)folder->summary, expunge, lf->changes, ex);
498         camel_local_folder_unlock(lf);
499
500         if (camel_folder_change_info_changed(lf->changes)) {
501                 camel_object_trigger_event(CAMEL_OBJECT(folder), "folder_changed", lf->changes);
502                 camel_folder_change_info_clear(lf->changes);
503         }
504 }
505
506 static void
507 local_expunge(CamelFolder *folder, CamelException *ex)
508 {
509         d(printf("expunge\n"));
510
511         /* Just do a sync with expunge, serves the same purpose */
512         /* call the callback directly, to avoid locking problems */
513         CAMEL_FOLDER_CLASS (CAMEL_OBJECT_GET_CLASS(folder))->sync(folder, TRUE, ex);
514 }
515
516 static void
517 local_delete(CamelFolder *folder)
518 {
519         CamelLocalFolder *lf = (CamelLocalFolder *)folder;
520         
521         if (lf->index)
522                 camel_index_delete(lf->index);
523
524         parent_class->delete(folder);
525 }
526
527 static void
528 local_rename(CamelFolder *folder, const char *newname)
529 {
530         CamelLocalFolder *lf = (CamelLocalFolder *)folder;
531         char *statepath;
532         CamelLocalStore *ls = (CamelLocalStore *)folder->parent_store;
533
534         d(printf("renaming local folder paths to '%s'\n", newname));
535
536         /* Sync? */
537
538         g_free(lf->folder_path);
539         g_free(lf->summary_path);
540         g_free(lf->index_path);
541
542         lf->folder_path = camel_local_store_get_full_path(ls, newname);
543         lf->summary_path = camel_local_store_get_meta_path(ls, newname, ".ev-summary");
544         lf->index_path = camel_local_store_get_meta_path(ls, newname, ".ibex");
545         statepath = camel_local_store_get_meta_path(ls, newname, ".cmeta");
546         camel_object_set(lf, NULL, CAMEL_OBJECT_STATE_FILE, statepath, NULL);
547         g_free(statepath);
548
549         /* FIXME: Poke some internals, sigh */
550         camel_folder_summary_set_filename(folder->summary, lf->summary_path);
551         g_free(((CamelLocalSummary *)folder->summary)->folder_path);
552         ((CamelLocalSummary *)folder->summary)->folder_path = g_strdup(lf->folder_path);
553
554         parent_class->rename(folder, newname);
555 }
556
557 static GPtrArray *
558 local_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
559 {
560         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
561         GPtrArray *matches;
562
563         CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
564
565         if (local_folder->search == NULL)
566                 local_folder->search = camel_folder_search_new();
567
568         camel_folder_search_set_folder(local_folder->search, folder);
569         camel_folder_search_set_body_index(local_folder->search, local_folder->index);
570         matches = camel_folder_search_search(local_folder->search, expression, NULL, ex);
571
572         CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
573
574         return matches;
575 }
576
577 static GPtrArray *
578 local_search_by_uids(CamelFolder *folder, const char *expression, GPtrArray *uids, CamelException *ex)
579 {
580         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
581         GPtrArray *matches;
582
583         if (uids->len == 0)
584                 return g_ptr_array_new();
585
586         CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
587
588         if (local_folder->search == NULL)
589                 local_folder->search = camel_folder_search_new();
590
591         camel_folder_search_set_folder(local_folder->search, folder);
592         camel_folder_search_set_body_index(local_folder->search, local_folder->index);
593         matches = camel_folder_search_search(local_folder->search, expression, uids, ex);
594
595         CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
596
597         return matches;
598 }
599
600 static void
601 local_search_free(CamelFolder *folder, GPtrArray * result)
602 {
603         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER(folder);
604
605         /* we need to lock this free because of the way search_free_result works */
606         /* FIXME: put the lock inside search_free_result */
607         CAMEL_LOCAL_FOLDER_LOCK(folder, search_lock);
608
609         camel_folder_search_free_result(local_folder->search, result);
610
611         CAMEL_LOCAL_FOLDER_UNLOCK(folder, search_lock);
612 }