1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
4  *
5  * This library is free software: you can redistribute it and/or modify it
6  * under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation.
8  *
9  * This library is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
12  * for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public License
15  * along with this library. If not, see <http://www.gnu.org/licenses/>.
16  *
17  * Authors: Michael Zucchi <notzed@ximian.com>
18  */
19 
20 #include "evolution-data-server-config.h"
21 
22 #include <errno.h>
23 #include <stdio.h>
24 #include <string.h>
25 #include <unistd.h>
26 #include <sys/stat.h>
27 
28 #include <glib/gi18n-lib.h>
29 #include <glib/gstdio.h>
30 
31 #include "camel-local-folder.h"
32 #include "camel-local-store.h"
33 
34 #define d(x)
35 
36 struct _CamelLocalStorePrivate {
37 	gboolean need_summary_check;
38 };
39 
40 enum {
41 	PROP_0,
42 	PROP_NEED_SUMMARY_CHECK
43 };
44 
G_DEFINE_TYPE_WITH_PRIVATE(CamelLocalStore,camel_local_store,CAMEL_TYPE_STORE)45 G_DEFINE_TYPE_WITH_PRIVATE (CamelLocalStore, camel_local_store, CAMEL_TYPE_STORE)
46 
47 static gint
48 xrename (const gchar *oldp,
49          const gchar *newp,
50          const gchar *prefix,
51          const gchar *suffix,
52          gint missingok,
53          GError **error)
54 {
55 	gchar *old, *new;
56 	gchar *basename;
57 	gint ret = -1;
58 	gint err = 0;
59 
60 	basename = g_strconcat (oldp, suffix, NULL);
61 	old = g_build_filename (prefix, basename, NULL);
62 	g_free (basename);
63 
64 	basename = g_strconcat (newp, suffix, NULL);
65 	new = g_build_filename (prefix, basename, NULL);
66 	g_free (basename);
67 
68 	d (printf ("renaming %s%s to %s%s\n", oldp, suffix, newp, suffix));
69 
70 	if (g_rename (old, new) == -1 &&
71 	    !(errno == ENOENT && missingok)) {
72 		err = errno;
73 		ret = -1;
74 	} else {
75 		ret = 0;
76 	}
77 
78 	if (ret == -1) {
79 		g_set_error (
80 			error, G_IO_ERROR,
81 			g_io_error_from_errno (err),
82 			_("Could not rename folder %s to %s: %s"),
83 			old, new, g_strerror (err));
84 	}
85 
86 	g_free (old);
87 	g_free (new);
88 	return ret;
89 }
90 
91 static void
local_store_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)92 local_store_set_property (GObject *object,
93                           guint property_id,
94                           const GValue *value,
95                           GParamSpec *pspec)
96 {
97 	switch (property_id) {
98 		case PROP_NEED_SUMMARY_CHECK:
99 			camel_local_store_set_need_summary_check (
100 				CAMEL_LOCAL_STORE (object),
101 				g_value_get_boolean (value));
102 			return;
103 	}
104 
105 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
106 }
107 
108 static void
local_store_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)109 local_store_get_property (GObject *object,
110                           guint property_id,
111                           GValue *value,
112                           GParamSpec *pspec)
113 {
114 	switch (property_id) {
115 		case PROP_NEED_SUMMARY_CHECK:
116 			g_value_set_boolean (
117 				value,
118 				camel_local_store_get_need_summary_check (
119 				CAMEL_LOCAL_STORE (object)));
120 			return;
121 	}
122 
123 	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
124 }
125 
126 static void
local_store_constructed(GObject * object)127 local_store_constructed (GObject *object)
128 {
129 	CamelLocalStore *local_store;
130 	CamelService *service;
131 	const gchar *uid;
132 
133 	local_store = CAMEL_LOCAL_STORE (object);
134 
135 	/* Chain up to parent's constructed() method. */
136 	G_OBJECT_CLASS (camel_local_store_parent_class)->constructed (object);
137 
138 	service = CAMEL_SERVICE (object);
139 	uid = camel_service_get_uid (service);
140 
141 	/* XXX This is Evolution-specific policy. */
142 	local_store->is_main_store = (g_strcmp0 (uid, "local") == 0);
143 }
144 
145 static gchar *
local_store_get_name(CamelService * service,gboolean brief)146 local_store_get_name (CamelService *service,
147                       gboolean brief)
148 {
149 	CamelLocalSettings *local_settings;
150 	CamelSettings *settings;
151 	gchar *path;
152 	gchar *name;
153 
154 	settings = camel_service_ref_settings (service);
155 
156 	local_settings = CAMEL_LOCAL_SETTINGS (settings);
157 	path = camel_local_settings_dup_path (local_settings);
158 
159 	g_object_unref (settings);
160 
161 	if (brief)
162 		name = g_strdup (path);
163 	else
164 		name = g_strdup_printf (_("Local mail file %s"), path);
165 
166 	g_free (path);
167 
168 	return name;
169 }
170 
171 static gboolean
local_store_can_refresh_folder(CamelStore * store,CamelFolderInfo * info,GError ** error)172 local_store_can_refresh_folder (CamelStore *store,
173                                 CamelFolderInfo *info,
174                                 GError **error)
175 {
176 	/* any local folder can be refreshed */
177 	return TRUE;
178 }
179 
180 static CamelFolder *
local_store_get_folder_sync(CamelStore * store,const gchar * folder_name,CamelStoreGetFolderFlags flags,GCancellable * cancellable,GError ** error)181 local_store_get_folder_sync (CamelStore *store,
182                              const gchar *folder_name,
183                              CamelStoreGetFolderFlags flags,
184                              GCancellable *cancellable,
185                              GError **error)
186 {
187 	CamelLocalSettings *local_settings;
188 	CamelSettings *settings;
189 	CamelService *service;
190 	CamelFolder *folder = NULL;
191 	struct stat st;
192 	gchar *path;
193 
194 	service = CAMEL_SERVICE (store);
195 
196 	settings= camel_service_ref_settings (service);
197 
198 	local_settings = CAMEL_LOCAL_SETTINGS (settings);
199 	path = camel_local_settings_dup_path (local_settings);
200 
201 	g_object_unref (settings);
202 
203 	if (!g_path_is_absolute (path)) {
204 		g_set_error (
205 			error, CAMEL_STORE_ERROR,
206 			CAMEL_STORE_ERROR_NO_FOLDER,
207 			_("Store root %s is not an absolute path"), path);
208 		goto exit;
209 	}
210 
211 	if (g_stat (path, &st) == 0) {
212 		if (!S_ISDIR (st.st_mode)) {
213 			g_set_error (
214 				error, CAMEL_STORE_ERROR,
215 				CAMEL_STORE_ERROR_NO_FOLDER,
216 				_("Store root %s is not a regular directory"), path);
217 			return NULL;
218 		}
219 		folder = (CamelFolder *) 0xdeadbeef;
220 		goto exit;
221 	}
222 
223 	if (errno != ENOENT
224 	    || (flags & CAMEL_STORE_FOLDER_CREATE) == 0) {
225 		g_set_error (
226 			error, G_IO_ERROR,
227 			g_io_error_from_errno (errno),
228 			_("Cannot get folder: %s: %s"),
229 			path, g_strerror (errno));
230 		goto exit;
231 	}
232 
233 	/* need to create the dir heirarchy */
234 	if (g_mkdir_with_parents (path, 0700) == -1 && errno != EEXIST) {
235 		g_set_error (
236 			error, G_IO_ERROR,
237 			g_io_error_from_errno (errno),
238 			_("Cannot get folder: %s: %s"),
239 			path, g_strerror (errno));
240 		goto exit;
241 	}
242 
243 	folder = (CamelFolder *) 0xdeadbeef;
244 
245 exit:
246 	g_free (path);
247 
248 	return folder;
249 }
250 
251 static CamelFolderInfo *
local_store_get_folder_info_sync(CamelStore * store,const gchar * top,CamelStoreGetFolderInfoFlags flags,GCancellable * cancellable,GError ** error)252 local_store_get_folder_info_sync (CamelStore *store,
253                                   const gchar *top,
254                                   CamelStoreGetFolderInfoFlags flags,
255                                   GCancellable *cancellable,
256                                   GError **error)
257 {
258 	/* FIXME: This is broken, but it corresponds to what was
259 	 * there before.
260 	 */
261 
262 	d (printf ("-- LOCAL STORE -- get folder info: %s\n", top));
263 
264 	return NULL;
265 }
266 
267 static CamelFolder *
local_store_get_inbox_folder_sync(CamelStore * store,GCancellable * cancellable,GError ** error)268 local_store_get_inbox_folder_sync (CamelStore *store,
269                                    GCancellable *cancellable,
270                                    GError **error)
271 {
272 	g_set_error (
273 		error, CAMEL_STORE_ERROR,
274 		CAMEL_STORE_ERROR_NO_FOLDER,
275 		_("Local stores do not have an inbox"));
276 
277 	return NULL;
278 }
279 
280 static CamelFolder *
local_store_get_junk_folder_sync(CamelStore * store,GCancellable * cancellable,GError ** error)281 local_store_get_junk_folder_sync (CamelStore *store,
282                                   GCancellable *cancellable,
283                                   GError **error)
284 {
285 	CamelFolder *folder;
286 
287 	/* Chain up to parent's get_junk_folder_sync() method. */
288 	folder = CAMEL_STORE_CLASS (camel_local_store_parent_class)->
289 		get_junk_folder_sync (store, cancellable, error);
290 
291 	if (folder) {
292 		CamelObject *object = CAMEL_OBJECT (folder);
293 		gchar *state;
294 
295 		state = camel_local_store_get_meta_path (
296 			CAMEL_LOCAL_STORE (store),
297 			CAMEL_VJUNK_NAME, ".cmeta");
298 		camel_object_set_state_filename (object, state);
299 		g_free (state);
300 
301 		/* no defaults? */
302 		camel_object_state_read (object);
303 	}
304 
305 	return folder;
306 }
307 
308 static CamelFolder *
local_store_get_trash_folder_sync(CamelStore * store,GCancellable * cancellable,GError ** error)309 local_store_get_trash_folder_sync (CamelStore *store,
310                                    GCancellable *cancellable,
311                                    GError **error)
312 {
313 	CamelFolder *folder;
314 
315 	/* Chain up to parent's get_trash_folder_sync() method. */
316 	folder = CAMEL_STORE_CLASS (camel_local_store_parent_class)->
317 		get_trash_folder_sync (store, cancellable, error);
318 
319 	if (folder) {
320 		CamelObject *object = CAMEL_OBJECT (folder);
321 		gchar *state;
322 
323 		state = camel_local_store_get_meta_path (
324 			CAMEL_LOCAL_STORE (store),
325 			CAMEL_VTRASH_NAME, ".cmeta");
326 		camel_object_set_state_filename (object, state);
327 		g_free (state);
328 
329 		/* no defaults? */
330 		camel_object_state_read (object);
331 	}
332 
333 	return folder;
334 }
335 
336 static CamelFolderInfo *
local_store_create_folder_sync(CamelStore * store,const gchar * parent_name,const gchar * folder_name,GCancellable * cancellable,GError ** error)337 local_store_create_folder_sync (CamelStore *store,
338                                 const gchar *parent_name,
339                                 const gchar *folder_name,
340                                 GCancellable *cancellable,
341                                 GError **error)
342 {
343 	CamelLocalSettings *local_settings;
344 	CamelSettings *settings;
345 	CamelService *service;
346 	CamelFolder *folder;
347 	CamelFolderInfo *info = NULL;
348 	gchar *name = NULL;
349 	gchar *path;
350 	struct stat st;
351 
352 	service = CAMEL_SERVICE (store);
353 
354 	settings = camel_service_ref_settings (service);
355 
356 	local_settings = CAMEL_LOCAL_SETTINGS (settings);
357 	path = camel_local_settings_dup_path (local_settings);
358 
359 	g_object_unref (settings);
360 
361 	/* This is a pretty hacky version of create folder, but should basically work */
362 
363 	if (!g_path_is_absolute (path)) {
364 		g_set_error (
365 			error, CAMEL_STORE_ERROR,
366 			CAMEL_STORE_ERROR_NO_FOLDER,
367 			_("Store root %s is not an absolute path"), path);
368 		goto exit;
369 	}
370 
371 	if (parent_name && *parent_name)
372 		name = g_strdup_printf ("%s/%s/%s", path, parent_name, folder_name);
373 	else
374 		name = g_strdup_printf ("%s/%s", path, folder_name);
375 
376 	if (g_stat (name, &st) == 0 || errno != ENOENT) {
377 		g_set_error (
378 			error, G_IO_ERROR,
379 			g_io_error_from_errno (errno),
380 			_("Cannot get folder: %s: %s"),
381 			name, g_strerror (errno));
382 		goto exit;
383 	}
384 
385 	g_free (name);
386 
387 	if (parent_name && *parent_name)
388 		name = g_strdup_printf ("%s/%s", parent_name, folder_name);
389 	else
390 		name = g_strdup_printf ("%s", folder_name);
391 
392 	folder = CAMEL_STORE_GET_CLASS (store)->get_folder_sync (
393 		store, name, CAMEL_STORE_FOLDER_CREATE, cancellable, error);
394 	if (folder) {
395 		g_object_unref (folder);
396 		info = CAMEL_STORE_GET_CLASS (store)->get_folder_info_sync (
397 			store, name, 0, cancellable, error);
398 	}
399 
400 exit:
401 	g_free (name);
402 	g_free (path);
403 
404 	return info;
405 }
406 
407 /* default implementation, only delete metadata */
408 static gboolean
local_store_delete_folder_sync(CamelStore * store,const gchar * folder_name,GCancellable * cancellable,GError ** error)409 local_store_delete_folder_sync (CamelStore *store,
410                                 const gchar *folder_name,
411                                 GCancellable *cancellable,
412                                 GError **error)
413 {
414 	CamelLocalSettings *local_settings;
415 	CamelSettings *settings;
416 	CamelService *service;
417 	CamelFolderInfo *fi;
418 	CamelFolder *lf;
419 	gchar *str = NULL;
420 	gchar *name;
421 	gchar *path;
422 	gboolean success = TRUE;
423 
424 	service = CAMEL_SERVICE (store);
425 
426 	settings = camel_service_ref_settings (service);
427 
428 	local_settings = CAMEL_LOCAL_SETTINGS (settings);
429 	path = camel_local_settings_dup_path (local_settings);
430 
431 	g_object_unref (settings);
432 
433 	/* remove metadata only */
434 	name = g_build_filename (path, folder_name, NULL);
435 	str = g_strdup_printf ("%s.ibex", name);
436 	if (camel_text_index_remove (str) == -1 && errno != ENOENT && errno != ENOTDIR) {
437 		g_set_error (
438 			error, G_IO_ERROR,
439 			g_io_error_from_errno (errno),
440 			_("Could not delete folder index file “%s”: %s"),
441 			str, g_strerror (errno));
442 		success = FALSE;
443 		goto exit;
444 	}
445 
446 	g_free (str);
447 	str = NULL;
448 
449 	if ((lf = camel_store_get_folder_sync (store, folder_name, 0, cancellable, NULL))) {
450 		CamelObject *object = CAMEL_OBJECT (lf);
451 		const gchar *state_filename;
452 
453 		state_filename = camel_object_get_state_filename (object);
454 		str = g_strdup (state_filename);
455 
456 		camel_object_set_state_filename (object, NULL);
457 
458 		g_object_unref (lf);
459 	}
460 
461 	if (str == NULL)
462 		str = g_strdup_printf ("%s.cmeta", name);
463 
464 	if (g_unlink (str) == -1 && errno != ENOENT && errno != ENOTDIR) {
465 		g_set_error (
466 			error, G_IO_ERROR,
467 			g_io_error_from_errno (errno),
468 			_("Could not delete folder meta file “%s”: %s"),
469 			str, g_strerror (errno));
470 		success = FALSE;
471 		goto exit;
472 	}
473 
474 	fi = camel_folder_info_new ();
475 	fi->full_name = g_strdup (folder_name);
476 	fi->display_name = g_path_get_basename (folder_name);
477 	fi->unread = -1;
478 
479 	camel_store_folder_deleted (store, fi);
480 	camel_folder_info_free (fi);
481 
482 exit:
483 	g_free (name);
484 	g_free (path);
485 	g_free (str);
486 
487 	return success;
488 }
489 
490 /* default implementation, rename all */
491 static gboolean
local_store_rename_folder_sync(CamelStore * store,const gchar * old,const gchar * new,GCancellable * cancellable,GError ** error)492 local_store_rename_folder_sync (CamelStore *store,
493                                 const gchar *old,
494                                 const gchar *new,
495                                 GCancellable *cancellable,
496                                 GError **error)
497 {
498 	CamelLocalFolder *folder;
499 	CamelLocalSettings *local_settings;
500 	CamelSettings *settings;
501 	CamelService *service;
502 	gchar *old_basename;
503 	gchar *new_basename;
504 	gchar *newibex;
505 	gchar *oldibex;
506 	gchar *path;
507 	gboolean success = TRUE;
508 
509 	service = CAMEL_SERVICE (store);
510 
511 	settings = camel_service_ref_settings (service);
512 
513 	local_settings = CAMEL_LOCAL_SETTINGS (settings);
514 	path = camel_local_settings_dup_path (local_settings);
515 
516 	g_object_unref (settings);
517 
518 	old_basename = g_strdup_printf ("%s.ibex", old);
519 	new_basename = g_strdup_printf ("%s.ibex", new);
520 
521 	oldibex = g_build_filename (path, old_basename, NULL);
522 	newibex = g_build_filename (path, new_basename, NULL);
523 
524 	g_free (old_basename);
525 	g_free (new_basename);
526 
527 	/* try to rollback failures, has obvious races */
528 
529 	d (printf ("local rename folder '%s' '%s'\n", old, new));
530 
531 	folder = camel_object_bag_get (camel_store_get_folders_bag (store), old);
532 	if (folder && folder->index) {
533 		if (camel_index_rename (folder->index, newibex) == -1)
534 			goto ibex_failed;
535 	} else {
536 		/* TODO camel_text_index_rename() should find
537 		 *      out if we have an active index itself? */
538 		if (camel_text_index_rename (oldibex, newibex) == -1)
539 			goto ibex_failed;
540 	}
541 
542 	if (xrename (old, new, path, ".ev-summary", TRUE, error))
543 		goto summary_failed;
544 
545 	if (xrename (old, new, path, ".ev-summary-meta", TRUE, error))
546 		goto summary_failed;
547 
548 	if (xrename (old, new, path, ".cmeta", TRUE, error))
549 		goto cmeta_failed;
550 
551 	if (xrename (old, new, path, "", FALSE, error))
552 		goto base_failed;
553 
554 	g_free (newibex);
555 	g_free (oldibex);
556 
557 	if (folder)
558 		g_object_unref (folder);
559 
560 	goto exit;
561 
562 	/* The (f)utility of this recovery effort is quesitonable */
563 
564 base_failed:
565 	xrename (new, old, path, ".cmeta", TRUE, NULL);
566 
567 cmeta_failed:
568 	xrename (new, old, path, ".ev-summary", TRUE, NULL);
569 	xrename (new, old, path, ".ev-summary-meta", TRUE, NULL);
570 summary_failed:
571 	if (folder) {
572 		if (folder->index)
573 			camel_index_rename (folder->index, oldibex);
574 	} else
575 		camel_text_index_rename (newibex, oldibex);
576 ibex_failed:
577 	if (error && !*error)
578 		g_set_error (
579 			error, G_IO_ERROR,
580 			g_io_error_from_errno (errno),
581 			_("Could not rename “%s”: %s"),
582 			old, g_strerror (errno));
583 
584 	g_free (newibex);
585 	g_free (oldibex);
586 
587 	if (folder)
588 		g_object_unref (folder);
589 
590 	success = FALSE;
591 
592 exit:
593 	g_free (path);
594 
595 	return success;
596 }
597 
598 static gchar *
local_store_get_full_path(CamelLocalStore * ls,const gchar * full_name)599 local_store_get_full_path (CamelLocalStore *ls,
600                            const gchar *full_name)
601 {
602 	CamelLocalSettings *local_settings;
603 	CamelSettings *settings;
604 	CamelService *service;
605 	gchar *filename;
606 	gchar *path;
607 
608 	service = CAMEL_SERVICE (ls);
609 
610 	settings = camel_service_ref_settings (service);
611 
612 	local_settings = CAMEL_LOCAL_SETTINGS (settings);
613 	path = camel_local_settings_dup_path (local_settings);
614 
615 	g_object_unref (settings);
616 
617 	filename = g_build_filename (path, full_name, NULL);
618 
619 	g_free (path);
620 
621 	return filename;
622 }
623 
624 static gchar *
local_store_get_meta_path(CamelLocalStore * ls,const gchar * full_name,const gchar * ext)625 local_store_get_meta_path (CamelLocalStore *ls,
626                            const gchar *full_name,
627                            const gchar *ext)
628 {
629 	CamelLocalSettings *local_settings;
630 	CamelSettings *settings;
631 	CamelService *service;
632 	gchar *basename;
633 	gchar *filename;
634 	gchar *path;
635 
636 	service = CAMEL_SERVICE (ls);
637 
638 	settings = camel_service_ref_settings (service);
639 
640 	local_settings = CAMEL_LOCAL_SETTINGS (settings);
641 	path = camel_local_settings_dup_path (local_settings);
642 
643 	g_object_unref (settings);
644 
645 	basename = g_strconcat (full_name, ext, NULL);
646 	filename = g_build_filename (path, basename, NULL);
647 	g_free (basename);
648 
649 	g_free (path);
650 
651 	return filename;
652 }
653 
654 static void
camel_local_store_class_init(CamelLocalStoreClass * class)655 camel_local_store_class_init (CamelLocalStoreClass *class)
656 {
657 	GObjectClass *object_class;
658 	CamelServiceClass *service_class;
659 	CamelStoreClass *store_class;
660 
661 	object_class = G_OBJECT_CLASS (class);
662 	object_class->set_property = local_store_set_property;
663 	object_class->get_property = local_store_get_property;
664 	object_class->constructed = local_store_constructed;
665 
666 	service_class = CAMEL_SERVICE_CLASS (class);
667 	service_class->settings_type = CAMEL_TYPE_LOCAL_SETTINGS;
668 	service_class->get_name = local_store_get_name;
669 
670 	store_class = CAMEL_STORE_CLASS (class);
671 	store_class->can_refresh_folder = local_store_can_refresh_folder;
672 	store_class->get_folder_sync = local_store_get_folder_sync;
673 	store_class->get_folder_info_sync = local_store_get_folder_info_sync;
674 	store_class->get_inbox_folder_sync = local_store_get_inbox_folder_sync;
675 	store_class->get_junk_folder_sync = local_store_get_junk_folder_sync;
676 	store_class->get_trash_folder_sync = local_store_get_trash_folder_sync;
677 	store_class->create_folder_sync = local_store_create_folder_sync;
678 	store_class->delete_folder_sync = local_store_delete_folder_sync;
679 	store_class->rename_folder_sync = local_store_rename_folder_sync;
680 
681 	class->get_full_path = local_store_get_full_path;
682 	class->get_meta_path = local_store_get_meta_path;
683 
684 	g_object_class_install_property (
685 		object_class,
686 		PROP_NEED_SUMMARY_CHECK,
687 		g_param_spec_boolean (
688 			"need-summary-check",
689 			"Need Summary Check",
690 			"Whether to check for unexpected file changes",
691 			TRUE,
692 			G_PARAM_READWRITE |
693 			G_PARAM_CONSTRUCT |
694 			G_PARAM_EXPLICIT_NOTIFY |
695 			G_PARAM_STATIC_STRINGS));
696 }
697 
698 static void
camel_local_store_init(CamelLocalStore * local_store)699 camel_local_store_init (CamelLocalStore *local_store)
700 {
701 	local_store->priv = camel_local_store_get_instance_private (local_store);
702 }
703 
704 /* Returns whether is this store used as 'On This Computer' main store */
705 gboolean
camel_local_store_is_main_store(CamelLocalStore * store)706 camel_local_store_is_main_store (CamelLocalStore *store)
707 {
708 	g_return_val_if_fail (store != NULL, FALSE);
709 
710 	return store->is_main_store;
711 }
712 
713 gchar *
camel_local_store_get_full_path(CamelLocalStore * store,const gchar * full_name)714 camel_local_store_get_full_path (CamelLocalStore *store,
715                                  const gchar *full_name)
716 {
717 	CamelLocalStoreClass *class;
718 
719 	g_return_val_if_fail (CAMEL_IS_LOCAL_STORE (store), NULL);
720 	/* XXX Guard against full_name == NULL? */
721 
722 	class = CAMEL_LOCAL_STORE_GET_CLASS (store);
723 	g_return_val_if_fail (class != NULL, NULL);
724 	g_return_val_if_fail (class->get_full_path != NULL, NULL);
725 
726 	return class->get_full_path (store, full_name);
727 }
728 
729 gchar *
camel_local_store_get_meta_path(CamelLocalStore * store,const gchar * full_name,const gchar * ext)730 camel_local_store_get_meta_path (CamelLocalStore *store,
731                                  const gchar *full_name,
732                                  const gchar *ext)
733 {
734 	CamelLocalStoreClass *class;
735 
736 	g_return_val_if_fail (CAMEL_IS_LOCAL_STORE (store), NULL);
737 	/* XXX Guard against full_name == NULL? */
738 	/* XXX Guard against ext == NULL? */
739 
740 	class = CAMEL_LOCAL_STORE_GET_CLASS (store);
741 	g_return_val_if_fail (class != NULL, NULL);
742 	g_return_val_if_fail (class->get_meta_path != NULL, NULL);
743 
744 	return class->get_meta_path (store, full_name, ext);
745 }
746 
747 guint32
camel_local_store_get_folder_type_by_full_name(CamelLocalStore * store,const gchar * full_name)748 camel_local_store_get_folder_type_by_full_name (CamelLocalStore *store,
749                                                 const gchar *full_name)
750 {
751 	g_return_val_if_fail (store != NULL, 0);
752 	g_return_val_if_fail (full_name != NULL, 0);
753 
754 	if (!camel_local_store_is_main_store (store))
755 		return CAMEL_FOLDER_TYPE_NORMAL;
756 
757 	if (g_ascii_strcasecmp (full_name, "Inbox") == 0)
758 		return CAMEL_FOLDER_TYPE_INBOX;
759 	else if (g_ascii_strcasecmp (full_name, "Outbox") == 0)
760 		return CAMEL_FOLDER_TYPE_OUTBOX;
761 	else if (g_ascii_strcasecmp (full_name, "Sent") == 0)
762 		return CAMEL_FOLDER_TYPE_SENT;
763 
764 	return CAMEL_FOLDER_TYPE_NORMAL;
765 }
766 
767 /**
768  * camel_local_store_get_need_summary_check:
769  * @store: a #CamelLocalStore
770  *
771  * Returns whether local mail files for @store should be check for
772  * consistency and the summary database synchronized with them.  This
773  * is necessary to handle another mail application altering the files,
774  * such as local mail delivery using fetchmail.
775  *
776  * Returns: whether to check for changes in local mail files
777  *
778  * Since: 3.2
779  **/
780 gboolean
camel_local_store_get_need_summary_check(CamelLocalStore * store)781 camel_local_store_get_need_summary_check (CamelLocalStore *store)
782 {
783 	g_return_val_if_fail (CAMEL_IS_LOCAL_STORE (store), FALSE);
784 
785 	return store->priv->need_summary_check;
786 }
787 
788 /**
789  * camel_local_store_set_need_summary_check:
790  * @store: a #CamelLocalStore
791  * @need_summary_check: whether to check for changes in local mail files
792  *
793  * Sets whether local mail files for @store should be checked for
794  * consistency and the summary database synchronized with them.  This
795  * is necessary to handle another mail application altering the files,
796  * such as local mail delivery using fetchmail.
797  *
798  * Since: 3.2
799  **/
800 void
camel_local_store_set_need_summary_check(CamelLocalStore * store,gboolean need_summary_check)801 camel_local_store_set_need_summary_check (CamelLocalStore *store,
802                                           gboolean need_summary_check)
803 {
804 	g_return_if_fail (CAMEL_IS_LOCAL_STORE (store));
805 
806 	if (store->priv->need_summary_check == need_summary_check)
807 		return;
808 
809 	store->priv->need_summary_check = need_summary_check;
810 
811 	g_object_notify (G_OBJECT (store), "need-summary-check");
812 }
813