updated changelog
[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 (C) 1999-2008 Novell, Inc. (www.novell.com)
6  *
7  * This library is free software you can redistribute it and/or modify it
8  * under the terms of the GNU Lesser General Public License as published by
9  * the Free Software Foundation.
10  *
11  * This library is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public License
17  * along with this library; if not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
24
25 #include <errno.h>
26 #include <fcntl.h>
27 #include <limits.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <unistd.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33
34 #include <glib/gi18n-lib.h>
35 #include <glib/gstdio.h>
36
37 #if !defined (G_OS_WIN32) && !defined (_POSIX_PATH_MAX)
38 #include <posix1_lim.h>
39 #endif
40
41 #include "camel-local-folder.h"
42 #include "camel-local-private.h"
43 #include "camel-local-store.h"
44 #include "camel-local-summary.h"
45
46 #define d(x) /*(printf("%s(%d): ", __FILE__, __LINE__),(x))*/
47
48 #ifndef PATH_MAX
49 #define PATH_MAX _POSIX_PATH_MAX
50 #endif
51
52 #define CAMEL_LOCAL_FOLDER_GET_PRIVATE(obj) \
53         (G_TYPE_INSTANCE_GET_PRIVATE \
54         ((obj), CAMEL_TYPE_LOCAL_FOLDER, CamelLocalFolderPrivate))
55
56 /* The custom property ID is a CamelArg artifact.
57  * It still identifies the property in state files. */
58 enum {
59         PROP_0,
60         PROP_INDEX_BODY = 0x2400
61 };
62
63 G_DEFINE_TYPE (CamelLocalFolder, camel_local_folder, CAMEL_TYPE_FOLDER)
64
65 static void
66 local_folder_set_property (GObject *object,
67                            guint property_id,
68                            const GValue *value,
69                            GParamSpec *pspec)
70 {
71         switch (property_id) {
72                 case PROP_INDEX_BODY:
73                         camel_local_folder_set_index_body (
74                                 CAMEL_LOCAL_FOLDER (object),
75                                 g_value_get_boolean (value));
76                         return;
77         }
78
79         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
80 }
81
82 static void
83 local_folder_get_property (GObject *object,
84                            guint property_id,
85                            GValue *value,
86                            GParamSpec *pspec)
87 {
88         switch (property_id) {
89                 case PROP_INDEX_BODY:
90                         g_value_set_boolean (
91                                 value, camel_local_folder_get_index_body (
92                                 CAMEL_LOCAL_FOLDER (object)));
93                         return;
94         }
95
96         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
97 }
98
99 static void
100 local_folder_dispose (GObject *object)
101 {
102         CamelFolder *folder;
103         CamelLocalFolder *local_folder;
104
105         folder = CAMEL_FOLDER (object);
106         local_folder = CAMEL_LOCAL_FOLDER (object);
107
108         if (folder->summary != NULL) {
109                 camel_local_summary_sync (
110                         CAMEL_LOCAL_SUMMARY (folder->summary),
111                         FALSE, local_folder->changes, NULL, NULL);
112                 g_object_unref (folder->summary);
113                 folder->summary = NULL;
114         }
115
116         if (local_folder->search != NULL) {
117                 g_object_unref (local_folder->search);
118                 local_folder->search = NULL;
119         }
120
121         if (local_folder->index != NULL) {
122                 g_object_unref (local_folder->index);
123                 local_folder->index = NULL;
124         }
125
126         /* Chain up to parent's dispose() method. */
127         G_OBJECT_CLASS (camel_local_folder_parent_class)->dispose (object);
128 }
129
130 static void
131 local_folder_finalize (GObject *object)
132 {
133         CamelLocalFolder *local_folder;
134
135         local_folder = CAMEL_LOCAL_FOLDER (object);
136
137         while (local_folder->locked > 0)
138                 camel_local_folder_unlock (local_folder);
139
140         g_free (local_folder->base_path);
141         g_free (local_folder->folder_path);
142         g_free (local_folder->index_path);
143
144         camel_folder_change_info_free (local_folder->changes);
145
146         g_mutex_clear (&local_folder->priv->search_lock);
147
148         /* Chain up to parent's finalize() method. */
149         G_OBJECT_CLASS (camel_local_folder_parent_class)->finalize (object);
150 }
151
152 static void
153 local_folder_constructed (GObject *object)
154 {
155         CamelLocalSettings *local_settings;
156         CamelProvider *provider;
157         CamelSettings *settings;
158         CamelService *service;
159         CamelFolder *folder;
160         CamelStore *parent_store;
161         const gchar *full_name;
162         const gchar *tmp;
163         gchar *description;
164         gchar *root_path;
165         gchar *path;
166
167         folder = CAMEL_FOLDER (object);
168         full_name = camel_folder_get_full_name (folder);
169         parent_store = camel_folder_get_parent_store (folder);
170
171         service = CAMEL_SERVICE (parent_store);
172         provider = camel_service_get_provider (service);
173
174         settings = camel_service_ref_settings (service);
175
176         local_settings = CAMEL_LOCAL_SETTINGS (settings);
177         root_path = camel_local_settings_dup_path (local_settings);
178
179         g_object_unref (settings);
180
181         if (root_path == NULL)
182                 return;
183
184         path = g_strdup_printf ("%s/%s", root_path, full_name);
185
186         if ((tmp = getenv ("HOME")) && strncmp (tmp, path, strlen (tmp)) == 0)
187                 /* Translators: This is used for a folder description,
188                  * for folders being under $HOME.  The first %s is replaced
189                  * with a relative path under $HOME, the second %s is
190                  * replaced with a protocol name, like mbox/maldir/... */
191                 description = g_strdup_printf (
192                         _("~%s (%s)"),
193                         path + strlen (tmp),
194                         provider->protocol);
195         else if ((tmp = "/var/spool/mail") && strncmp (tmp, path, strlen (tmp)) == 0)
196                 /* Translators: This is used for a folder description, for
197                  * folders being under /var/spool/mail.  The first %s is
198                  * replaced with a relative path under /var/spool/mail,
199                  * the second %s is replaced with a protocol name, like
200                  * mbox/maldir/... */
201                 description = g_strdup_printf (
202                         _("mailbox: %s (%s)"),
203                         path + strlen (tmp),
204                         provider->protocol);
205         else if ((tmp = "/var/mail") && strncmp (tmp, path, strlen (tmp)) == 0)
206                 /* Translators: This is used for a folder description, for
207                  * folders being under /var/mail.  The first %s is replaced
208                  * with a relative path under /var/mail, the second %s is
209                  * replaced with a protocol name, like mbox/maldir/... */
210                 description = g_strdup_printf (
211                         _("mailbox: %s (%s)"),
212                         path + strlen (tmp),
213                         provider->protocol);
214         else
215                 /* Translators: This is used for a folder description.
216                  * The first %s is replaced with a folder's full path,
217                  * the second %s is replaced with a protocol name, like
218                  * mbox/maldir/... */
219                 description = g_strdup_printf (
220                         _("%s (%s)"), path,
221                         provider->protocol);
222
223         camel_folder_set_description (folder, description);
224
225         g_free (description);
226         g_free (root_path);
227         g_free (path);
228 }
229
230 static GPtrArray *
231 local_folder_search_by_expression (CamelFolder *folder,
232                                    const gchar *expression,
233                                    GCancellable *cancellable,
234                                    GError **error)
235 {
236         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER (folder);
237         GPtrArray *matches;
238
239         CAMEL_LOCAL_FOLDER_LOCK (folder, search_lock);
240
241         if (local_folder->search == NULL)
242                 local_folder->search = camel_folder_search_new ();
243
244         camel_folder_search_set_folder (local_folder->search, folder);
245         if (camel_local_folder_get_index_body (local_folder))
246                 camel_folder_search_set_body_index (local_folder->search, local_folder->index);
247         else
248                 camel_folder_search_set_body_index (local_folder->search, NULL);
249         matches = camel_folder_search_search (local_folder->search, expression, NULL, cancellable, error);
250
251         CAMEL_LOCAL_FOLDER_UNLOCK (folder, search_lock);
252
253         return matches;
254 }
255
256 static GPtrArray *
257 local_folder_search_by_uids (CamelFolder *folder,
258                              const gchar *expression,
259                              GPtrArray *uids,
260                              GCancellable *cancellable,
261                              GError **error)
262 {
263         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER (folder);
264         GPtrArray *matches;
265
266         if (uids->len == 0)
267                 return g_ptr_array_new ();
268
269         CAMEL_LOCAL_FOLDER_LOCK (folder, search_lock);
270
271         if (local_folder->search == NULL)
272                 local_folder->search = camel_folder_search_new ();
273
274         camel_folder_search_set_folder (local_folder->search, folder);
275         if (camel_local_folder_get_index_body (local_folder))
276                 camel_folder_search_set_body_index (local_folder->search, local_folder->index);
277         else
278                 camel_folder_search_set_body_index (local_folder->search, NULL);
279         matches = camel_folder_search_search (local_folder->search, expression, uids, cancellable, error);
280
281         CAMEL_LOCAL_FOLDER_UNLOCK (folder, search_lock);
282
283         return matches;
284 }
285
286 static void
287 local_folder_search_free (CamelFolder *folder,
288                           GPtrArray *result)
289 {
290         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER (folder);
291
292         /* we need to lock this free because of the way search_free_result works */
293         /* FIXME: put the lock inside search_free_result */
294         CAMEL_LOCAL_FOLDER_LOCK (folder, search_lock);
295
296         camel_folder_search_free_result (local_folder->search, result);
297
298         CAMEL_LOCAL_FOLDER_UNLOCK (folder, search_lock);
299 }
300
301 static void
302 local_folder_delete (CamelFolder *folder)
303 {
304         CamelLocalFolder *lf = (CamelLocalFolder *) folder;
305
306         if (lf->index)
307                 camel_index_delete (lf->index);
308
309         CAMEL_FOLDER_CLASS (camel_local_folder_parent_class)->delete_ (folder);
310 }
311
312 static void
313 local_folder_rename (CamelFolder *folder,
314                      const gchar *newname)
315 {
316         CamelLocalFolder *lf = (CamelLocalFolder *) folder;
317         gchar *statepath;
318         CamelLocalStore *ls;
319         CamelStore *parent_store;
320
321         parent_store = camel_folder_get_parent_store (folder);
322         ls = CAMEL_LOCAL_STORE (parent_store);
323
324         d (printf ("renaming local folder paths to '%s'\n", newname));
325
326         /* Sync? */
327
328         g_free (lf->folder_path);
329         g_free (lf->index_path);
330
331         lf->folder_path = camel_local_store_get_full_path (ls, newname);
332         lf->index_path = camel_local_store_get_meta_path (ls, newname, ".ibex");
333         statepath = camel_local_store_get_meta_path (ls, newname, ".cmeta");
334         camel_object_set_state_filename (CAMEL_OBJECT (lf), statepath);
335         g_free (statepath);
336
337         /* FIXME: Poke some internals, sigh */
338         g_free (((CamelLocalSummary *) folder->summary)->folder_path);
339         ((CamelLocalSummary *) folder->summary)->folder_path = g_strdup (lf->folder_path);
340
341         CAMEL_FOLDER_CLASS (camel_local_folder_parent_class)->rename (folder, newname);
342 }
343
344 static guint32
345 local_folder_count_by_expression (CamelFolder *folder,
346                                   const gchar *expression,
347                                   GCancellable *cancellable,
348                                   GError **error)
349 {
350         CamelLocalFolder *local_folder = CAMEL_LOCAL_FOLDER (folder);
351         gint matches;
352
353         CAMEL_LOCAL_FOLDER_LOCK (folder, search_lock);
354
355         if (local_folder->search == NULL)
356                 local_folder->search = camel_folder_search_new ();
357
358         camel_folder_search_set_folder (local_folder->search, folder);
359         if (camel_local_folder_get_index_body (local_folder))
360                 camel_folder_search_set_body_index (local_folder->search, local_folder->index);
361         else
362                 camel_folder_search_set_body_index (local_folder->search, NULL);
363         matches = camel_folder_search_count (local_folder->search, expression, cancellable, error);
364
365         CAMEL_LOCAL_FOLDER_UNLOCK (folder, search_lock);
366
367         return matches;
368 }
369
370 static GPtrArray *
371 local_folder_get_uncached_uids (CamelFolder *folder,
372                                 GPtrArray *uids,
373                                 GError **error)
374 {
375         /* By default, we would have everything local.
376          * No need to fetch from anywhere. */
377         return g_ptr_array_new ();
378 }
379
380 static gboolean
381 local_folder_expunge_sync (CamelFolder *folder,
382                            GCancellable *cancellable,
383                            GError **error)
384 {
385         /* Just do a sync with expunge, serves the same purpose */
386         /* call the callback directly, to avoid locking problems */
387         return CAMEL_FOLDER_GET_CLASS (folder)->synchronize_sync (
388                 folder, TRUE, cancellable, error);
389 }
390
391 static gboolean
392 local_folder_refresh_info_sync (CamelFolder *folder,
393                                 GCancellable *cancellable,
394                                 GError **error)
395 {
396         CamelStore *parent_store;
397         CamelLocalFolder *lf = (CamelLocalFolder *) folder;
398         gboolean need_summary_check;
399
400         parent_store = camel_folder_get_parent_store (folder);
401
402         need_summary_check = camel_local_store_get_need_summary_check (
403                 CAMEL_LOCAL_STORE (parent_store));
404
405         if (need_summary_check &&
406             camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, cancellable, error) == -1)
407                 return FALSE;
408
409         if (camel_folder_change_info_changed (lf->changes)) {
410                 camel_folder_changed (folder, lf->changes);
411                 camel_folder_change_info_clear (lf->changes);
412         }
413
414         return TRUE;
415 }
416
417 static gboolean
418 local_folder_synchronize_sync (CamelFolder *folder,
419                                gboolean expunge,
420                                GCancellable *cancellable,
421                                GError **error)
422 {
423         CamelLocalFolder *lf = CAMEL_LOCAL_FOLDER (folder);
424         gboolean success;
425
426         d (printf ("local sync '%s' , expunge=%s\n", folder->full_name, expunge?"true":"false"));
427
428         if (camel_local_folder_lock (lf, CAMEL_LOCK_WRITE, error) == -1)
429                 return FALSE;
430
431         camel_object_state_write (CAMEL_OBJECT (lf));
432
433         /* if sync fails, we'll pass it up on exit through ex */
434         success = (camel_local_summary_sync (
435                 (CamelLocalSummary *) folder->summary,
436                 expunge, lf->changes, cancellable, error) == 0);
437         camel_local_folder_unlock (lf);
438
439         if (camel_folder_change_info_changed (lf->changes)) {
440                 camel_folder_changed (folder, lf->changes);
441                 camel_folder_change_info_clear (lf->changes);
442         }
443
444         return success;
445 }
446
447 static gint
448 local_folder_lock (CamelLocalFolder *lf,
449                    CamelLockType type,
450                    GError **error)
451 {
452         return 0;
453 }
454
455 static void
456 local_folder_unlock (CamelLocalFolder *lf)
457 {
458         /* nothing */
459 }
460
461 static void
462 camel_local_folder_class_init (CamelLocalFolderClass *class)
463 {
464         GObjectClass *object_class;
465         CamelFolderClass *folder_class;
466
467         g_type_class_add_private (class, sizeof (CamelLocalFolderPrivate));
468
469         object_class = G_OBJECT_CLASS (class);
470         object_class->set_property = local_folder_set_property;
471         object_class->get_property = local_folder_get_property;
472         object_class->dispose = local_folder_dispose;
473         object_class->finalize = local_folder_finalize;
474         object_class->constructed = local_folder_constructed;
475
476         folder_class = CAMEL_FOLDER_CLASS (class);
477         folder_class->search_by_expression = local_folder_search_by_expression;
478         folder_class->search_by_uids = local_folder_search_by_uids;
479         folder_class->search_free = local_folder_search_free;
480         folder_class->delete_ = local_folder_delete;
481         folder_class->rename = local_folder_rename;
482         folder_class->count_by_expression = local_folder_count_by_expression;
483         folder_class->get_uncached_uids = local_folder_get_uncached_uids;
484         folder_class->expunge_sync = local_folder_expunge_sync;
485         folder_class->refresh_info_sync = local_folder_refresh_info_sync;
486         folder_class->synchronize_sync = local_folder_synchronize_sync;
487
488         class->lock = local_folder_lock;
489         class->unlock = local_folder_unlock;
490
491         g_object_class_install_property (
492                 object_class,
493                 PROP_INDEX_BODY,
494                 g_param_spec_boolean (
495                         "index-body",
496                         "Index Body",
497                         _("_Index message body data"),
498                         FALSE,
499                         G_PARAM_READWRITE |
500                         CAMEL_PARAM_PERSISTENT));
501 }
502
503 static void
504 camel_local_folder_init (CamelLocalFolder *local_folder)
505 {
506         CamelFolder *folder = CAMEL_FOLDER (local_folder);
507
508         local_folder->priv = CAMEL_LOCAL_FOLDER_GET_PRIVATE (local_folder);
509         g_mutex_init (&local_folder->priv->search_lock);
510
511         folder->folder_flags |= CAMEL_FOLDER_HAS_SUMMARY_CAPABILITY;
512
513         folder->permanent_flags = CAMEL_MESSAGE_ANSWERED |
514             CAMEL_MESSAGE_DELETED | CAMEL_MESSAGE_DRAFT |
515             CAMEL_MESSAGE_FLAGGED | CAMEL_MESSAGE_SEEN |
516             CAMEL_MESSAGE_ANSWERED_ALL | CAMEL_MESSAGE_USER;
517
518         folder->summary = NULL;
519         local_folder->search = NULL;
520 }
521
522 CamelLocalFolder *
523 camel_local_folder_construct (CamelLocalFolder *lf,
524                               guint32 flags,
525                               GCancellable *cancellable,
526                               GError **error)
527 {
528         CamelFolder *folder;
529         CamelLocalSettings *local_settings;
530         CamelSettings *settings;
531         CamelService *service;
532         gchar *statepath;
533 #ifndef G_OS_WIN32
534 #ifdef __GLIBC__
535         gchar *folder_path;
536 #else
537         gchar folder_path[PATH_MAX];
538 #endif
539         struct stat st;
540 #endif
541         gint forceindex;
542         CamelLocalStore *ls;
543         CamelStore *parent_store;
544         const gchar *full_name;
545         gboolean need_summary_check;
546
547         folder = CAMEL_FOLDER (lf);
548         full_name = camel_folder_get_full_name (folder);
549         parent_store = camel_folder_get_parent_store (folder);
550
551         service = CAMEL_SERVICE (parent_store);
552
553         settings = camel_service_ref_settings (service);
554
555         local_settings = CAMEL_LOCAL_SETTINGS (settings);
556         lf->base_path = camel_local_settings_dup_path (local_settings);
557
558         g_object_unref (settings);
559
560         ls = CAMEL_LOCAL_STORE (parent_store);
561         need_summary_check = camel_local_store_get_need_summary_check (ls);
562
563         lf->folder_path = camel_local_store_get_full_path (ls, full_name);
564         lf->index_path = camel_local_store_get_meta_path (ls, full_name, ".ibex");
565         statepath = camel_local_store_get_meta_path (ls, full_name, ".cmeta");
566
567         camel_object_set_state_filename (CAMEL_OBJECT (lf), statepath);
568         g_free (statepath);
569
570         lf->flags = flags;
571
572         if (camel_object_state_read (CAMEL_OBJECT (lf)) == -1) {
573                 /* No metadata - load defaults and persitify */
574                 camel_local_folder_set_index_body (lf, TRUE);
575                 camel_object_state_write (CAMEL_OBJECT (lf));
576         }
577
578         /* XXX Canonicalizing the folder path portably is a messy affair.
579          *     The proposed GLib function in [1] would be useful here.
580          *
581          *     [1] https://bugzilla.gnome.org/show_bug.cgi?id=111848
582          */
583 #ifndef G_OS_WIN32
584         /* follow any symlinks to the mailbox */
585         if (g_lstat (lf->folder_path, &st) != -1 && S_ISLNK (st.st_mode) &&
586 #ifdef __GLIBC__
587             (folder_path = realpath (lf->folder_path, NULL)) != NULL) {
588 #else
589             realpath (lf->folder_path, folder_path) != NULL) {
590 #endif
591                 g_free (lf->folder_path);
592                 lf->folder_path = g_strdup (folder_path);
593 #ifdef __GLIBC__
594                 /* Not a typo.  Use free() here, not g_free().
595                  * The path string was allocated by realpath(). */
596                 free (folder_path);
597 #endif
598         }
599 #endif
600         lf->changes = camel_folder_change_info_new ();
601
602         /* TODO: Remove the following line, it is a temporary workaround to remove
603          * the old-format 'ibex' files that might be lying around */
604         g_unlink (lf->index_path);
605
606         /* FIXME: Need to run indexing off of the setv method */
607
608         /* if we have no/invalid index file, force it */
609         forceindex = camel_text_index_check (lf->index_path) == -1;
610         if (lf->flags & CAMEL_STORE_FOLDER_BODY_INDEX) {
611                 gint flag = O_RDWR | O_CREAT;
612
613                 if (forceindex)
614                         flag |= O_TRUNC;
615
616                 lf->index = (CamelIndex *) camel_text_index_new (lf->index_path, flag);
617                 if (lf->index == NULL) {
618                         /* yes, this isn't fatal at all */
619                         g_warning ("Could not open/create index file: %s: indexing not performed", g_strerror (errno));
620                         forceindex = FALSE;
621                         /* record that we dont have an index afterall */
622                         lf->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
623                 }
624         } else {
625                 /* if we do have an index file, remove it (?) */
626                 if (forceindex == FALSE)
627                         camel_text_index_remove (lf->index_path);
628                 forceindex = FALSE;
629         }
630
631         folder->summary = (CamelFolderSummary *) CAMEL_LOCAL_FOLDER_GET_CLASS (lf)->create_summary (lf, lf->folder_path, lf->index);
632         if (!(flags & CAMEL_STORE_IS_MIGRATING) && !camel_local_summary_load ((CamelLocalSummary *) folder->summary, forceindex, NULL)) {
633                 /* ? */
634                 if (need_summary_check &&
635                     camel_local_summary_check ((CamelLocalSummary *) folder->summary, lf->changes, cancellable, error) == 0) {
636                         /* we sync here so that any hard work setting up the folder isn't lost */
637                         if (camel_local_summary_sync ((CamelLocalSummary *) folder->summary, FALSE, lf->changes, cancellable, error) == -1) {
638                                 g_object_unref (folder);
639                                 return NULL;
640                         }
641                 }
642         }
643
644         /* TODO: This probably shouldn't be here? */
645         if ((flags & CAMEL_STORE_FOLDER_CREATE) != 0) {
646                 CamelFolderInfo *fi;
647
648                 /* Use 'recursive' mode, even for just created folder, to have set whether
649                    the folder has children or not properly. */
650                 fi = camel_store_get_folder_info_sync (parent_store, full_name, CAMEL_STORE_FOLDER_INFO_RECURSIVE, NULL, NULL);
651                 g_return_val_if_fail (fi != NULL, lf);
652
653                 camel_store_folder_created (parent_store, fi);
654                 camel_folder_info_free (fi);
655         }
656
657         return lf;
658 }
659
660 gboolean
661 camel_local_folder_get_index_body (CamelLocalFolder *local_folder)
662 {
663         g_return_val_if_fail (CAMEL_IS_LOCAL_FOLDER (local_folder), FALSE);
664
665         return (local_folder->flags & CAMEL_STORE_FOLDER_BODY_INDEX);
666 }
667
668 void
669 camel_local_folder_set_index_body (CamelLocalFolder *local_folder,
670                                    gboolean index_body)
671 {
672         g_return_if_fail (CAMEL_IS_LOCAL_FOLDER (local_folder));
673
674         if (index_body)
675                 local_folder->flags |= CAMEL_STORE_FOLDER_BODY_INDEX;
676         else
677                 local_folder->flags &= ~CAMEL_STORE_FOLDER_BODY_INDEX;
678
679         g_object_notify (G_OBJECT (local_folder), "index-body");
680 }
681
682 /* lock the folder, may be called repeatedly (with matching unlock calls),
683  * with type the same or less than the first call */
684 gint
685 camel_local_folder_lock (CamelLocalFolder *lf,
686                          CamelLockType type,
687                          GError **error)
688 {
689         if (lf->locked > 0) {
690                 /* lets be anal here - its important the code knows what its doing */
691                 g_assert (lf->locktype == type || lf->locktype == CAMEL_LOCK_WRITE);
692         } else {
693                 if (CAMEL_LOCAL_FOLDER_GET_CLASS (lf)->lock (lf, type, error) == -1)
694                         return -1;
695                 lf->locktype = type;
696         }
697
698         lf->locked++;
699
700         return 0;
701 }
702
703 /* unlock folder */
704 gint
705 camel_local_folder_unlock (CamelLocalFolder *lf)
706 {
707         g_assert (lf->locked > 0);
708         lf->locked--;
709         if (lf->locked == 0)
710                 CAMEL_LOCAL_FOLDER_GET_CLASS (lf)->unlock (lf);
711
712         return 0;
713 }
714
715 void
716 set_cannot_get_message_ex (GError **error,
717                            gint err_code,
718                            const gchar *msgID,
719                            const gchar *folder_path,
720                            const gchar *detailErr)
721 {
722         /* Translators: The first %s is replaced with a message ID,
723          * the second %s is replaced with the folder path,
724          * the third %s is replaced with a detailed error string */
725         g_set_error (
726                 error, CAMEL_ERROR, err_code,
727                 _("Cannot get message %s from folder %s\n%s"),
728                 msgID, folder_path, detailErr);
729 }