1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* camel-store.c : Abstract class for an email store */
6 * Bertrand Guiheneuf <bertrand@helixcode.com>
7 * Dan Winship <danw@ximian.com>
9 * Copyright (C) 1999-2008 Novell, Inc. (www.novell.com)
11 * This program is free software; you can redistribute it and/or
12 * modify it under the terms of version 2 of the GNU Lesser General Public
13 * License as published by the Free Software Foundation.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
33 #include <sys/types.h>
35 #include <glib/gi18n-lib.h>
38 #include "camel-debug.h"
39 #include "camel-folder.h"
40 #include "camel-marshal.h"
41 #include "camel-session.h"
42 #include "camel-store.h"
43 #include "camel-store-settings.h"
44 #include "camel-subscribable.h"
45 #include "camel-vtrash-folder.h"
50 #define CAMEL_STORE_GET_PRIVATE(obj) \
51 (G_TYPE_INSTANCE_GET_PRIVATE \
52 ((obj), CAMEL_TYPE_STORE, CamelStorePrivate))
54 typedef struct _AsyncContext AsyncContext;
55 typedef struct _SignalData SignalData;
57 struct _CamelStorePrivate {
58 GRecMutex folder_lock; /* for locking folder operations */
61 struct _AsyncContext {
70 CamelFolderInfo *folder_info;
76 CamelFolderInfo *folder_info;
88 static guint signals[LAST_SIGNAL];
89 static GInitableIface *parent_initable_interface;
91 /* Forward Declarations */
92 static void camel_store_initable_init (GInitableIface *interface);
94 G_DEFINE_ABSTRACT_TYPE_WITH_CODE (
95 CamelStore, camel_store, CAMEL_TYPE_SERVICE,
96 G_IMPLEMENT_INTERFACE (
97 G_TYPE_INITABLE, camel_store_initable_init))
100 async_context_free (AsyncContext *async_context)
102 g_free (async_context->folder_name_1);
103 g_free (async_context->folder_name_2);
105 if (async_context->folder != NULL)
106 g_object_unref (async_context->folder);
108 camel_folder_info_free (async_context->folder_info);
110 g_slice_free (AsyncContext, async_context);
114 signal_data_free (SignalData *signal_data)
116 if (signal_data->store != NULL)
117 g_object_unref (signal_data->store);
119 if (signal_data->folder != NULL)
120 g_object_unref (signal_data->folder);
122 if (signal_data->folder_info != NULL)
123 camel_folder_info_free (signal_data->folder_info);
125 g_free (signal_data->folder_name);
127 g_slice_free (SignalData, signal_data);
131 store_emit_folder_created_cb (gpointer user_data)
133 SignalData *signal_data = user_data;
137 signals[FOLDER_CREATED], 0,
138 signal_data->folder_info);
144 store_emit_folder_deleted_cb (gpointer user_data)
146 SignalData *signal_data = user_data;
150 signals[FOLDER_DELETED], 0,
151 signal_data->folder_info);
157 store_emit_folder_opened_cb (gpointer user_data)
159 SignalData *signal_data = user_data;
163 signals[FOLDER_OPENED], 0,
164 signal_data->folder);
170 store_emit_folder_renamed_cb (gpointer user_data)
172 SignalData *signal_data = user_data;
176 signals[FOLDER_RENAMED], 0,
177 signal_data->folder_name,
178 signal_data->folder_info);
184 * ignore_no_such_table_exception:
185 * Clears the exception 'ex' when it's the 'no such table' exception.
188 ignore_no_such_table_exception (GError **error)
190 if (error == NULL || *error == NULL)
193 if (g_ascii_strncasecmp ((*error)->message, "no such table", 13) == 0)
194 g_clear_error (error);
197 /* deletes folder/removes it from the folder cache, if it's there */
199 cs_delete_cached_folder (CamelStore *store,
200 const gchar *folder_name)
203 CamelVeeFolder *vfolder;
205 if (store->folders == NULL)
208 folder = camel_object_bag_get (store->folders, folder_name);
212 if (store->flags & CAMEL_STORE_VTRASH) {
213 vfolder = camel_object_bag_get (
214 store->folders, CAMEL_VTRASH_NAME);
215 if (vfolder != NULL) {
216 camel_vee_folder_remove_folder (vfolder, folder, NULL);
217 g_object_unref (vfolder);
221 if (store->flags & CAMEL_STORE_VJUNK) {
222 vfolder = camel_object_bag_get (
223 store->folders, CAMEL_VJUNK_NAME);
224 if (vfolder != NULL) {
225 camel_vee_folder_remove_folder (vfolder, folder, NULL);
226 g_object_unref (vfolder);
230 camel_folder_delete (folder);
232 camel_object_bag_remove (store->folders, folder);
233 g_object_unref (folder);
237 store_get_special (CamelStore *store,
238 camel_vtrash_folder_t type)
244 folder = camel_vtrash_folder_new (store, type);
245 folders = camel_object_bag_list (store->folders);
246 for (i = 0; i < folders->len; i++) {
247 if (!CAMEL_IS_VTRASH_FOLDER (folders->pdata[i]))
248 camel_vee_folder_add_folder ((CamelVeeFolder *) folder, (CamelFolder *) folders->pdata[i], NULL);
249 g_object_unref (folders->pdata[i]);
251 g_ptr_array_free (folders, TRUE);
257 store_finalize (GObject *object)
259 CamelStore *store = CAMEL_STORE (object);
261 if (store->folders != NULL)
262 camel_object_bag_destroy (store->folders);
264 g_rec_mutex_clear (&store->priv->folder_lock);
266 if (store->cdb_r != NULL) {
267 camel_db_close (store->cdb_r);
272 /* Chain up to parent's finalize() method. */
273 G_OBJECT_CLASS (camel_store_parent_class)->finalize (object);
277 store_constructed (GObject *object)
280 CamelStoreClass *class;
282 /* Chain up to parent's constructed() method. */
283 G_OBJECT_CLASS (camel_store_parent_class)->constructed (object);
285 store = CAMEL_STORE (object);
286 class = CAMEL_STORE_GET_CLASS (store);
288 g_return_if_fail (class->hash_folder_name != NULL);
289 g_return_if_fail (class->equal_folder_name != NULL);
291 store->folders = camel_object_bag_new (
292 class->hash_folder_name,
293 class->equal_folder_name,
294 (CamelCopyFunc) g_strdup, g_free);
298 store_can_refresh_folder (CamelStore *store,
299 CamelFolderInfo *info,
302 return ((info->flags & CAMEL_FOLDER_TYPE_MASK) == CAMEL_FOLDER_TYPE_INBOX);
306 store_get_inbox_folder_sync (CamelStore *store,
307 GCancellable *cancellable,
310 CamelStoreClass *class;
313 class = CAMEL_STORE_GET_CLASS (store);
314 g_return_val_if_fail (class->get_folder_sync != NULL, NULL);
316 /* Assume the inbox's name is "inbox" and open with default flags. */
317 folder = class->get_folder_sync (store, "inbox", 0, cancellable, error);
318 CAMEL_CHECK_GERROR (store, get_folder_sync, folder != NULL, error);
324 store_get_junk_folder_sync (CamelStore *store,
325 GCancellable *cancellable,
328 return store_get_special (store, CAMEL_VTRASH_FOLDER_JUNK);
332 store_get_trash_folder_sync (CamelStore *store,
333 GCancellable *cancellable,
336 return store_get_special (store, CAMEL_VTRASH_FOLDER_TRASH);
340 store_synchronize_sync (CamelStore *store,
342 GCancellable *cancellable,
347 gboolean success = TRUE;
349 GError *local_error = NULL;
352 /* ensure all folders are used when expunging */
353 CamelFolderInfo *root, *fi;
355 folders = g_ptr_array_new ();
356 root = camel_store_get_folder_info_sync (store, NULL, CAMEL_STORE_FOLDER_INFO_RECURSIVE | CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, NULL, NULL);
359 CamelFolderInfo *next;
361 if ((fi->flags & CAMEL_FOLDER_NOSELECT) == 0) {
364 fldr = camel_store_get_folder_sync (store, fi->full_name, 0, NULL, NULL);
366 g_ptr_array_add (folders, fldr);
389 camel_store_free_folder_info_full (store, root);
391 /* sync only folders opened until now */
392 folders = camel_object_bag_list (store->folders);
395 /* We don't sync any vFolders, that is used to update certain
396 * vfolder queries mainly, and we're really only interested in
397 * storing/expunging the physical mails. */
398 for (i = 0; i < folders->len; i++) {
399 folder = folders->pdata[i];
400 if (!CAMEL_IS_VEE_FOLDER (folder)
401 && local_error == NULL) {
402 camel_folder_synchronize_sync (
403 folder, expunge, cancellable, &local_error);
404 ignore_no_such_table_exception (&local_error);
406 g_object_unref (folder);
409 if (local_error != NULL) {
410 g_propagate_error (error, local_error);
414 g_ptr_array_free (folders, TRUE);
420 store_noop_sync (CamelStore *store,
421 GCancellable *cancellable,
428 store_get_folder_thread (GSimpleAsyncResult *simple,
430 GCancellable *cancellable)
432 AsyncContext *async_context;
433 GError *error = NULL;
435 async_context = g_simple_async_result_get_op_res_gpointer (simple);
437 async_context->folder = camel_store_get_folder_sync (
438 CAMEL_STORE (object), async_context->folder_name_1,
439 async_context->flags, cancellable, &error);
442 g_simple_async_result_take_error (simple, error);
446 store_get_folder (CamelStore *store,
447 const gchar *folder_name,
448 CamelStoreGetFolderFlags flags,
450 GCancellable *cancellable,
451 GAsyncReadyCallback callback,
454 GSimpleAsyncResult *simple;
455 AsyncContext *async_context;
457 async_context = g_slice_new0 (AsyncContext);
458 async_context->folder_name_1 = g_strdup (folder_name);
459 async_context->flags = flags;
461 simple = g_simple_async_result_new (
462 G_OBJECT (store), callback, user_data, store_get_folder);
464 g_simple_async_result_set_check_cancellable (simple, cancellable);
466 g_simple_async_result_set_op_res_gpointer (
467 simple, async_context, (GDestroyNotify) async_context_free);
469 g_simple_async_result_run_in_thread (
470 simple, store_get_folder_thread, io_priority, cancellable);
472 g_object_unref (simple);
476 store_get_folder_finish (CamelStore *store,
477 GAsyncResult *result,
480 GSimpleAsyncResult *simple;
481 AsyncContext *async_context;
483 g_return_val_if_fail (
484 g_simple_async_result_is_valid (
485 result, G_OBJECT (store), store_get_folder), NULL);
487 simple = G_SIMPLE_ASYNC_RESULT (result);
488 async_context = g_simple_async_result_get_op_res_gpointer (simple);
490 if (g_simple_async_result_propagate_error (simple, error))
493 return g_object_ref (async_context->folder);
497 store_get_folder_info_thread (GSimpleAsyncResult *simple,
499 GCancellable *cancellable)
501 AsyncContext *async_context;
502 GError *error = NULL;
504 async_context = g_simple_async_result_get_op_res_gpointer (simple);
506 async_context->folder_info = camel_store_get_folder_info_sync (
507 CAMEL_STORE (object), async_context->folder_name_1,
508 async_context->flags, cancellable, &error);
511 g_simple_async_result_take_error (simple, error);
515 store_get_folder_info (CamelStore *store,
517 CamelStoreGetFolderInfoFlags flags,
519 GCancellable *cancellable,
520 GAsyncReadyCallback callback,
523 GSimpleAsyncResult *simple;
524 AsyncContext *async_context;
526 async_context = g_slice_new0 (AsyncContext);
527 async_context->folder_name_1 = g_strdup (top);
528 async_context->flags = flags;
530 simple = g_simple_async_result_new (
531 G_OBJECT (store), callback,
532 user_data, store_get_folder_info);
534 g_simple_async_result_set_check_cancellable (simple, cancellable);
536 g_simple_async_result_set_op_res_gpointer (
537 simple, async_context, (GDestroyNotify) async_context_free);
539 g_simple_async_result_run_in_thread (
540 simple, store_get_folder_info_thread,
541 io_priority, cancellable);
543 g_object_unref (simple);
546 static CamelFolderInfo *
547 store_get_folder_info_finish (CamelStore *store,
548 GAsyncResult *result,
551 GSimpleAsyncResult *simple;
552 AsyncContext *async_context;
553 CamelFolderInfo *folder_info;
555 g_return_val_if_fail (
556 g_simple_async_result_is_valid (
557 result, G_OBJECT (store), store_get_folder_info), NULL);
559 simple = G_SIMPLE_ASYNC_RESULT (result);
560 async_context = g_simple_async_result_get_op_res_gpointer (simple);
562 if (g_simple_async_result_propagate_error (simple, error))
565 folder_info = async_context->folder_info;
566 async_context->folder_info = NULL;
572 store_get_inbox_folder_thread (GSimpleAsyncResult *simple,
574 GCancellable *cancellable)
576 AsyncContext *async_context;
577 GError *error = NULL;
579 async_context = g_simple_async_result_get_op_res_gpointer (simple);
581 async_context->folder = camel_store_get_inbox_folder_sync (
582 CAMEL_STORE (object), cancellable, &error);
585 g_simple_async_result_take_error (simple, error);
589 store_get_inbox_folder (CamelStore *store,
591 GCancellable *cancellable,
592 GAsyncReadyCallback callback,
595 GSimpleAsyncResult *simple;
596 AsyncContext *async_context;
598 async_context = g_slice_new0 (AsyncContext);
600 simple = g_simple_async_result_new (
601 G_OBJECT (store), callback,
602 user_data, store_get_inbox_folder);
604 g_simple_async_result_set_check_cancellable (simple, cancellable);
606 g_simple_async_result_set_op_res_gpointer (
607 simple, async_context, (GDestroyNotify) async_context_free);
609 g_simple_async_result_run_in_thread (
610 simple, store_get_inbox_folder_thread,
611 io_priority, cancellable);
613 g_object_unref (simple);
617 store_get_inbox_folder_finish (CamelStore *store,
618 GAsyncResult *result,
621 GSimpleAsyncResult *simple;
622 AsyncContext *async_context;
624 g_return_val_if_fail (
625 g_simple_async_result_is_valid (
626 result, G_OBJECT (store), store_get_inbox_folder), NULL);
628 simple = G_SIMPLE_ASYNC_RESULT (result);
629 async_context = g_simple_async_result_get_op_res_gpointer (simple);
631 if (g_simple_async_result_propagate_error (simple, error))
634 return g_object_ref (async_context->folder);
638 store_get_junk_folder_thread (GSimpleAsyncResult *simple,
640 GCancellable *cancellable)
642 AsyncContext *async_context;
643 GError *error = NULL;
645 async_context = g_simple_async_result_get_op_res_gpointer (simple);
647 async_context->folder = camel_store_get_junk_folder_sync (
648 CAMEL_STORE (object), cancellable, &error);
651 g_simple_async_result_take_error (simple, error);
655 store_get_junk_folder (CamelStore *store,
657 GCancellable *cancellable,
658 GAsyncReadyCallback callback,
661 GSimpleAsyncResult *simple;
662 AsyncContext *async_context;
664 async_context = g_slice_new0 (AsyncContext);
666 simple = g_simple_async_result_new (
667 G_OBJECT (store), callback,
668 user_data, store_get_junk_folder);
670 g_simple_async_result_set_check_cancellable (simple, cancellable);
672 g_simple_async_result_set_op_res_gpointer (
673 simple, async_context, (GDestroyNotify) async_context_free);
675 g_simple_async_result_run_in_thread (
676 simple, store_get_junk_folder_thread,
677 io_priority, cancellable);
679 g_object_unref (simple);
683 store_get_junk_folder_finish (CamelStore *store,
684 GAsyncResult *result,
687 GSimpleAsyncResult *simple;
688 AsyncContext *async_context;
690 g_return_val_if_fail (
691 g_simple_async_result_is_valid (
692 result, G_OBJECT (store), store_get_junk_folder), NULL);
694 simple = G_SIMPLE_ASYNC_RESULT (result);
695 async_context = g_simple_async_result_get_op_res_gpointer (simple);
697 if (g_simple_async_result_propagate_error (simple, error))
700 return g_object_ref (async_context->folder);
704 store_get_trash_folder_thread (GSimpleAsyncResult *simple,
706 GCancellable *cancellable)
708 AsyncContext *async_context;
709 GError *error = NULL;
711 async_context = g_simple_async_result_get_op_res_gpointer (simple);
713 async_context->folder = camel_store_get_trash_folder_sync (
714 CAMEL_STORE (object), cancellable, &error);
717 g_simple_async_result_take_error (simple, error);
721 store_get_trash_folder (CamelStore *store,
723 GCancellable *cancellable,
724 GAsyncReadyCallback callback,
727 GSimpleAsyncResult *simple;
728 AsyncContext *async_context;
730 async_context = g_slice_new0 (AsyncContext);
732 simple = g_simple_async_result_new (
733 G_OBJECT (store), callback,
734 user_data, store_get_trash_folder);
736 g_simple_async_result_set_check_cancellable (simple, cancellable);
738 g_simple_async_result_set_op_res_gpointer (
739 simple, async_context, (GDestroyNotify) async_context_free);
741 g_simple_async_result_run_in_thread (
742 simple, store_get_trash_folder_thread,
743 io_priority, cancellable);
745 g_object_unref (simple);
749 store_get_trash_folder_finish (CamelStore *store,
750 GAsyncResult *result,
753 GSimpleAsyncResult *simple;
754 AsyncContext *async_context;
756 g_return_val_if_fail (
757 g_simple_async_result_is_valid (
758 result, G_OBJECT (store), store_get_trash_folder), NULL);
760 simple = G_SIMPLE_ASYNC_RESULT (result);
761 async_context = g_simple_async_result_get_op_res_gpointer (simple);
763 if (g_simple_async_result_propagate_error (simple, error))
766 return g_object_ref (async_context->folder);
770 store_create_folder_thread (GSimpleAsyncResult *simple,
772 GCancellable *cancellable)
774 AsyncContext *async_context;
775 GError *error = NULL;
777 async_context = g_simple_async_result_get_op_res_gpointer (simple);
779 async_context->folder_info = camel_store_create_folder_sync (
780 CAMEL_STORE (object), async_context->folder_name_1,
781 async_context->folder_name_2, cancellable, &error);
784 g_simple_async_result_take_error (simple, error);
788 store_create_folder (CamelStore *store,
789 const gchar *parent_name,
790 const gchar *folder_name,
792 GCancellable *cancellable,
793 GAsyncReadyCallback callback,
796 GSimpleAsyncResult *simple;
797 AsyncContext *async_context;
799 async_context = g_slice_new0 (AsyncContext);
800 async_context->folder_name_1 = g_strdup (parent_name);
801 async_context->folder_name_2 = g_strdup (folder_name);
803 simple = g_simple_async_result_new (
804 G_OBJECT (store), callback, user_data, store_create_folder);
806 g_simple_async_result_set_check_cancellable (simple, cancellable);
808 g_simple_async_result_set_op_res_gpointer (
809 simple, async_context, (GDestroyNotify) async_context_free);
811 g_simple_async_result_run_in_thread (
812 simple, store_create_folder_thread, io_priority, cancellable);
814 g_object_unref (simple);
817 static CamelFolderInfo *
818 store_create_folder_finish (CamelStore *store,
819 GAsyncResult *result,
822 GSimpleAsyncResult *simple;
823 AsyncContext *async_context;
824 CamelFolderInfo *folder_info;
826 g_return_val_if_fail (
827 g_simple_async_result_is_valid (
828 result, G_OBJECT (store), store_create_folder), NULL);
830 simple = G_SIMPLE_ASYNC_RESULT (result);
831 async_context = g_simple_async_result_get_op_res_gpointer (simple);
833 if (g_simple_async_result_propagate_error (simple, error))
836 folder_info = async_context->folder_info;
837 async_context->folder_info = NULL;
843 store_delete_folder_thread (GSimpleAsyncResult *simple,
845 GCancellable *cancellable)
847 AsyncContext *async_context;
848 GError *error = NULL;
850 async_context = g_simple_async_result_get_op_res_gpointer (simple);
852 camel_store_delete_folder_sync (
853 CAMEL_STORE (object), async_context->folder_name_1,
854 cancellable, &error);
857 g_simple_async_result_take_error (simple, error);
861 store_delete_folder (CamelStore *store,
862 const gchar *folder_name,
864 GCancellable *cancellable,
865 GAsyncReadyCallback callback,
868 GSimpleAsyncResult *simple;
869 AsyncContext *async_context;
871 async_context = g_slice_new0 (AsyncContext);
872 async_context->folder_name_1 = g_strdup (folder_name);
874 simple = g_simple_async_result_new (
875 G_OBJECT (store), callback, user_data, store_delete_folder);
877 g_simple_async_result_set_check_cancellable (simple, cancellable);
879 g_simple_async_result_set_op_res_gpointer (
880 simple, async_context, (GDestroyNotify) async_context_free);
882 g_simple_async_result_run_in_thread (
883 simple, store_delete_folder_thread, io_priority, cancellable);
885 g_object_unref (simple);
889 store_delete_folder_finish (CamelStore *store,
890 GAsyncResult *result,
893 GSimpleAsyncResult *simple;
895 g_return_val_if_fail (
896 g_simple_async_result_is_valid (
897 result, G_OBJECT (store), store_delete_folder), FALSE);
899 simple = G_SIMPLE_ASYNC_RESULT (result);
901 /* Assume success unless a GError is set. */
902 return !g_simple_async_result_propagate_error (simple, error);
906 store_rename_folder_thread (GSimpleAsyncResult *simple,
908 GCancellable *cancellable)
910 AsyncContext *async_context;
911 GError *error = NULL;
913 async_context = g_simple_async_result_get_op_res_gpointer (simple);
915 camel_store_rename_folder_sync (
916 CAMEL_STORE (object), async_context->folder_name_1,
917 async_context->folder_name_2, cancellable, &error);
920 g_simple_async_result_take_error (simple, error);
924 store_rename_folder (CamelStore *store,
925 const gchar *old_name,
926 const gchar *new_name,
928 GCancellable *cancellable,
929 GAsyncReadyCallback callback,
932 GSimpleAsyncResult *simple;
933 AsyncContext *async_context;
935 async_context = g_slice_new0 (AsyncContext);
936 async_context->folder_name_1 = g_strdup (old_name);
937 async_context->folder_name_2 = g_strdup (new_name);
939 simple = g_simple_async_result_new (
940 G_OBJECT (store), callback, user_data, store_rename_folder);
942 g_simple_async_result_set_check_cancellable (simple, cancellable);
944 g_simple_async_result_set_op_res_gpointer (
945 simple, async_context, (GDestroyNotify) async_context_free);
947 g_simple_async_result_run_in_thread (
948 simple, store_rename_folder_thread, io_priority, cancellable);
950 g_object_unref (simple);
954 store_rename_folder_finish (CamelStore *store,
955 GAsyncResult *result,
958 GSimpleAsyncResult *simple;
960 g_return_val_if_fail (
961 g_simple_async_result_is_valid (
962 result, G_OBJECT (store), store_rename_folder), FALSE);
964 simple = G_SIMPLE_ASYNC_RESULT (result);
966 /* Assume success unless a GError is set. */
967 return !g_simple_async_result_propagate_error (simple, error);
971 store_synchronize_thread (GSimpleAsyncResult *simple,
973 GCancellable *cancellable)
975 AsyncContext *async_context;
976 GError *error = NULL;
978 async_context = g_simple_async_result_get_op_res_gpointer (simple);
980 camel_store_synchronize_sync (
981 CAMEL_STORE (object), async_context->expunge,
982 cancellable, &error);
985 g_simple_async_result_take_error (simple, error);
989 store_synchronize (CamelStore *store,
992 GCancellable *cancellable,
993 GAsyncReadyCallback callback,
996 GSimpleAsyncResult *simple;
997 AsyncContext *async_context;
999 async_context = g_slice_new0 (AsyncContext);
1000 async_context->expunge = expunge;
1002 simple = g_simple_async_result_new (
1003 G_OBJECT (store), callback, user_data, store_synchronize);
1005 g_simple_async_result_set_check_cancellable (simple, cancellable);
1007 g_simple_async_result_set_op_res_gpointer (
1008 simple, async_context, (GDestroyNotify) async_context_free);
1010 g_simple_async_result_run_in_thread (
1011 simple, store_synchronize_thread, io_priority, cancellable);
1013 g_object_unref (simple);
1017 store_synchronize_finish (CamelStore *store,
1018 GAsyncResult *result,
1021 GSimpleAsyncResult *simple;
1023 g_return_val_if_fail (
1024 g_simple_async_result_is_valid (
1025 result, G_OBJECT (store), store_synchronize), FALSE);
1027 simple = G_SIMPLE_ASYNC_RESULT (result);
1029 /* Assume success unless a GError is set. */
1030 return !g_simple_async_result_propagate_error (simple, error);
1034 store_noop_thread (GSimpleAsyncResult *simple,
1036 GCancellable *cancellable)
1038 GError *error = NULL;
1040 camel_store_noop_sync (CAMEL_STORE (object), cancellable, &error);
1043 g_simple_async_result_take_error (simple, error);
1047 store_noop (CamelStore *store,
1049 GCancellable *cancellable,
1050 GAsyncReadyCallback callback,
1053 GSimpleAsyncResult *simple;
1055 simple = g_simple_async_result_new (
1056 G_OBJECT (store), callback, user_data, store_noop);
1058 g_simple_async_result_set_check_cancellable (simple, cancellable);
1060 g_simple_async_result_run_in_thread (
1061 simple, store_noop_thread, io_priority, cancellable);
1063 g_object_unref (simple);
1067 store_noop_finish (CamelStore *store,
1068 GAsyncResult *result,
1071 GSimpleAsyncResult *simple;
1073 g_return_val_if_fail (
1074 g_simple_async_result_is_valid (
1075 result, G_OBJECT (store), store_noop), FALSE);
1077 simple = G_SIMPLE_ASYNC_RESULT (result);
1079 /* Assume success unless a GError is set. */
1080 return !g_simple_async_result_propagate_error (simple, error);
1084 store_initable_init (GInitable *initable,
1085 GCancellable *cancellable,
1089 CamelService *service;
1090 const gchar *user_dir;
1093 store = CAMEL_STORE (initable);
1095 /* Chain up to parent interface's init() method. */
1096 if (!parent_initable_interface->init (initable, cancellable, error))
1099 service = CAMEL_SERVICE (initable);
1100 if ((store->flags & CAMEL_STORE_USE_CACHE_DIR) != 0)
1101 user_dir = camel_service_get_user_cache_dir (service);
1103 user_dir = camel_service_get_user_data_dir (service);
1105 if (g_mkdir_with_parents (user_dir, S_IRWXU) == -1) {
1106 g_set_error_literal (
1107 error, G_FILE_ERROR,
1108 g_file_error_from_errno (errno),
1109 g_strerror (errno));
1113 /* This is for reading from the store */
1114 filename = g_build_filename (user_dir, CAMEL_DB_FILE, NULL);
1115 store->cdb_r = camel_db_open (filename, error);
1118 if (store->cdb_r == NULL)
1121 if (camel_db_create_folders_table (store->cdb_r, error))
1124 /* keep cb_w to not break the ABI */
1125 store->cdb_w = store->cdb_r;
1131 camel_store_class_init (CamelStoreClass *class)
1133 GObjectClass *object_class;
1134 CamelServiceClass *service_class;
1136 g_type_class_add_private (class, sizeof (CamelStorePrivate));
1138 object_class = G_OBJECT_CLASS (class);
1139 object_class->finalize = store_finalize;
1140 object_class->constructed = store_constructed;
1142 service_class = CAMEL_SERVICE_CLASS (class);
1143 service_class->settings_type = CAMEL_TYPE_STORE_SETTINGS;
1145 class->hash_folder_name = g_str_hash;
1146 class->equal_folder_name = g_str_equal;
1147 class->can_refresh_folder = store_can_refresh_folder;
1149 class->get_inbox_folder_sync = store_get_inbox_folder_sync;
1150 class->get_junk_folder_sync = store_get_junk_folder_sync;
1151 class->get_trash_folder_sync = store_get_trash_folder_sync;
1152 class->synchronize_sync = store_synchronize_sync;
1153 class->noop_sync = store_noop_sync;
1155 class->get_folder = store_get_folder;
1156 class->get_folder_finish = store_get_folder_finish;
1157 class->get_folder_info = store_get_folder_info;
1158 class->get_folder_info_finish = store_get_folder_info_finish;
1159 class->get_inbox_folder = store_get_inbox_folder;
1160 class->get_inbox_folder_finish = store_get_inbox_folder_finish;
1161 class->get_junk_folder = store_get_junk_folder;
1162 class->get_junk_folder_finish = store_get_junk_folder_finish;
1163 class->get_trash_folder = store_get_trash_folder;
1164 class->get_trash_folder_finish = store_get_trash_folder_finish;
1165 class->create_folder = store_create_folder;
1166 class->create_folder_finish = store_create_folder_finish;
1167 class->delete_folder = store_delete_folder;
1168 class->delete_folder_finish = store_delete_folder_finish;
1169 class->rename_folder = store_rename_folder;
1170 class->rename_folder_finish = store_rename_folder_finish;
1171 class->synchronize = store_synchronize;
1172 class->synchronize_finish = store_synchronize_finish;
1173 class->noop = store_noop;
1174 class->noop_finish = store_noop_finish;
1176 signals[FOLDER_CREATED] = g_signal_new (
1178 G_OBJECT_CLASS_TYPE (class),
1180 G_STRUCT_OFFSET (CamelStoreClass, folder_created),
1182 g_cclosure_marshal_VOID__POINTER,
1186 signals[FOLDER_DELETED] = g_signal_new (
1188 G_OBJECT_CLASS_TYPE (class),
1190 G_STRUCT_OFFSET (CamelStoreClass, folder_deleted),
1192 g_cclosure_marshal_VOID__POINTER,
1196 signals[FOLDER_OPENED] = g_signal_new (
1198 G_OBJECT_CLASS_TYPE (class),
1200 G_STRUCT_OFFSET (CamelStoreClass, folder_opened),
1202 g_cclosure_marshal_VOID__OBJECT,
1206 signals[FOLDER_RENAMED] = g_signal_new (
1208 G_OBJECT_CLASS_TYPE (class),
1210 G_STRUCT_OFFSET (CamelStoreClass, folder_renamed),
1212 camel_marshal_VOID__STRING_POINTER,
1219 camel_store_initable_init (GInitableIface *interface)
1221 parent_initable_interface = g_type_interface_peek_parent (interface);
1223 interface->init = store_initable_init;
1227 camel_store_init (CamelStore *store)
1229 store->priv = CAMEL_STORE_GET_PRIVATE (store);
1231 /* Default CamelStore capabilities:
1233 * - Include a virtual Junk folder.
1234 * - Include a virtual Trash folder.
1235 * - Allow creating/deleting/renaming folders.
1239 CAMEL_STORE_VTRASH |
1240 CAMEL_STORE_CAN_EDIT_FOLDERS;
1242 store->mode = CAMEL_STORE_READ | CAMEL_STORE_WRITE;
1244 g_rec_mutex_init (&store->priv->folder_lock);
1247 G_DEFINE_QUARK (camel-store-error-quark, camel_store_error)
1250 * camel_store_folder_created:
1251 * @store: a #CamelStore
1252 * @folder_info: information about the created folder
1254 * Emits the #CamelStore::folder-created signal from an idle source on
1255 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1257 * This function is only intended for Camel providers.
1262 camel_store_folder_created (CamelStore *store,
1263 CamelFolderInfo *folder_info)
1265 CamelSession *session;
1266 SignalData *signal_data;
1268 g_return_if_fail (CAMEL_IS_STORE (store));
1269 g_return_if_fail (folder_info != NULL);
1271 session = camel_service_get_session (CAMEL_SERVICE (store));
1273 signal_data = g_slice_new0 (SignalData);
1274 signal_data->store = g_object_ref (store);
1275 signal_data->folder_info = camel_folder_info_clone (folder_info);
1277 camel_session_idle_add (
1278 session, G_PRIORITY_DEFAULT_IDLE,
1279 store_emit_folder_created_cb,
1280 signal_data, (GDestroyNotify) signal_data_free);
1284 * camel_store_folder_deleted:
1285 * @store: a #CamelStore
1286 * @folder_info: information about the deleted folder
1288 * Emits the #CamelStore::folder-deleted signal from an idle source on
1289 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1291 * This function is only intended for Camel providers.
1296 camel_store_folder_deleted (CamelStore *store,
1297 CamelFolderInfo *folder_info)
1299 CamelSession *session;
1300 SignalData *signal_data;
1302 g_return_if_fail (CAMEL_IS_STORE (store));
1303 g_return_if_fail (folder_info != NULL);
1305 session = camel_service_get_session (CAMEL_SERVICE (store));
1307 signal_data = g_slice_new0 (SignalData);
1308 signal_data->store = g_object_ref (store);
1309 signal_data->folder_info = camel_folder_info_clone (folder_info);
1311 camel_session_idle_add (
1312 session, G_PRIORITY_DEFAULT_IDLE,
1313 store_emit_folder_deleted_cb,
1314 signal_data, (GDestroyNotify) signal_data_free);
1318 * camel_store_folder_opened:
1319 * @store: a #CamelStore
1320 * @folder: the #CamelFolder that was opened
1322 * Emits the #CamelStore::folder-opened signal from an idle source on
1323 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1325 * This function is only intended for Camel providers.
1330 camel_store_folder_opened (CamelStore *store,
1331 CamelFolder *folder)
1333 CamelSession *session;
1334 SignalData *signal_data;
1336 g_return_if_fail (CAMEL_IS_STORE (store));
1337 g_return_if_fail (CAMEL_IS_FOLDER (folder));
1339 session = camel_service_get_session (CAMEL_SERVICE (store));
1341 signal_data = g_slice_new0 (SignalData);
1342 signal_data->store = g_object_ref (store);
1343 signal_data->folder = g_object_ref (folder);
1345 camel_session_idle_add (
1346 session, G_PRIORITY_DEFAULT_IDLE,
1347 store_emit_folder_opened_cb,
1348 signal_data, (GDestroyNotify) signal_data_free);
1352 * camel_store_folder_renamed:
1353 * @store: a #CamelStore
1354 * @old_name: the old name of the folder
1355 * @folder_info: information about the renamed folder
1357 * Emits the #CamelStore::folder-renamed signal from an idle source on
1358 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1360 * This function is only intended for Camel providers.
1365 camel_store_folder_renamed (CamelStore *store,
1366 const gchar *old_name,
1367 CamelFolderInfo *folder_info)
1369 CamelSession *session;
1370 SignalData *signal_data;
1372 g_return_if_fail (CAMEL_IS_STORE (store));
1373 g_return_if_fail (old_name != NULL);
1374 g_return_if_fail (folder_info != NULL);
1376 session = camel_service_get_session (CAMEL_SERVICE (store));
1378 signal_data = g_slice_new0 (SignalData);
1379 signal_data->store = g_object_ref (store);
1380 signal_data->folder_info = camel_folder_info_clone (folder_info);
1381 signal_data->folder_name = g_strdup (old_name);
1383 camel_session_idle_add (
1384 session, G_PRIORITY_DEFAULT_IDLE,
1385 store_emit_folder_renamed_cb,
1386 signal_data, (GDestroyNotify) signal_data_free);
1390 add_special_info (CamelStore *store,
1391 CamelFolderInfo *info,
1393 const gchar *translated,
1394 gboolean unread_count,
1395 CamelFolderInfoFlags flags)
1397 CamelFolderInfo *fi, *vinfo, *parent;
1399 g_return_if_fail (CAMEL_IS_STORE (store));
1400 g_return_if_fail (info != NULL);
1403 for (fi = info; fi; fi = fi->next) {
1404 if (!strcmp (fi->full_name, name))
1410 /* We're going to replace the physical Trash/Junk
1411 * folder with our vTrash/vJunk folder. */
1413 g_free (vinfo->full_name);
1414 g_free (vinfo->display_name);
1416 /* There wasn't a Trash/Junk folder so create a new
1418 vinfo = camel_folder_info_new ();
1420 g_assert (parent != NULL);
1423 CAMEL_FOLDER_NOINFERIORS |
1424 CAMEL_FOLDER_SUBSCRIBED;
1426 /* link it into the right spot */
1427 vinfo->next = parent->next;
1428 parent->next = vinfo;
1431 /* Fill in the new fields */
1432 vinfo->flags |= flags;
1433 vinfo->full_name = g_strdup (name);
1434 vinfo->display_name = g_strdup (translated);
1441 dump_fi (CamelFolderInfo *fi,
1446 s = g_alloca (depth + 1);
1447 memset (s, ' ', depth);
1451 printf ("%sfull_name: %s\n", s, fi->full_name);
1452 printf ("%sflags: %08x\n", s, fi->flags);
1453 dump_fi (fi->child, depth + 2);
1459 * camel_store_free_folder_info:
1460 * @store: a #CamelStore
1461 * @fi: a #CamelFolderInfo as gotten via camel_store_get_folder_info()
1463 * Frees the data returned by camel_store_get_folder_info(). If @fi is %NULL,
1464 * nothing is done, the routine simply returns.
1467 camel_store_free_folder_info (CamelStore *store,
1468 CamelFolderInfo *fi)
1470 CamelStoreClass *class;
1472 g_return_if_fail (CAMEL_IS_STORE (store));
1477 class = CAMEL_STORE_GET_CLASS (store);
1478 g_return_if_fail (class->free_folder_info != NULL);
1480 class->free_folder_info (store, fi);
1484 * camel_store_free_folder_info_full:
1485 * @store: a #CamelStore
1486 * @fi: a #CamelFolderInfo as gotten via camel_store_get_folder_info()
1488 * An implementation for #CamelStore::free_folder_info. Frees all
1492 camel_store_free_folder_info_full (CamelStore *store,
1493 CamelFolderInfo *fi)
1495 camel_folder_info_free (fi);
1499 * camel_store_free_folder_info_nop:
1500 * @store: a #CamelStore
1501 * @fi: a #CamelFolderInfo as gotten via camel_store_get_folder_info()
1503 * An implementation for #CamelStore::free_folder_info. Does nothing.
1506 camel_store_free_folder_info_nop (CamelStore *store,
1507 CamelFolderInfo *fi)
1513 * camel_folder_info_free:
1514 * @fi: a #CamelFolderInfo
1519 camel_folder_info_free (CamelFolderInfo *fi)
1522 camel_folder_info_free (fi->next);
1523 camel_folder_info_free (fi->child);
1524 g_free (fi->full_name);
1525 g_free (fi->display_name);
1526 g_slice_free (CamelFolderInfo, fi);
1531 * camel_folder_info_new:
1533 * Allocates a new #CamelFolderInfo instance. Free it with
1534 * camel_folder_info_free().
1536 * Returns: a new #CamelFolderInfo instance
1541 camel_folder_info_new (void)
1543 return g_slice_new0 (CamelFolderInfo);
1547 folder_info_cmp (gconstpointer ap,
1550 const CamelFolderInfo *a = ((CamelFolderInfo **) ap)[0];
1551 const CamelFolderInfo *b = ((CamelFolderInfo **) bp)[0];
1553 return strcmp (a->full_name, b->full_name);
1557 * camel_folder_info_build:
1558 * @folders: an array of #CamelFolderInfo
1559 * @namespace_: an ignorable prefix on the folder names
1560 * @separator: the hieararchy separator character
1561 * @short_names: %TRUE if the (short) name of a folder is the part after
1562 * the last @separator in the full name. %FALSE if it is the full name.
1564 * This takes an array of folders and attaches them together according
1565 * to the hierarchy described by their full_names and @separator. If
1566 * @namespace_ is non-%NULL, then it will be ignored as a full_name
1567 * prefix, for purposes of comparison. If necessary,
1568 * camel_folder_info_build() will create additional #CamelFolderInfo with
1569 * %NULL urls to fill in gaps in the tree. The value of @short_names
1570 * is used in constructing the names of these intermediate folders.
1572 * NOTE: This is deprected, do not use this.
1573 * FIXME: remove this/move it to imap, which is the only user of it now.
1575 * Returns: the top level of the tree of linked folder info.
1578 camel_folder_info_build (GPtrArray *folders,
1579 const gchar *namespace_,
1581 gboolean short_names)
1583 CamelFolderInfo *fi, *pfi, *top = NULL, *tail = NULL;
1588 if (namespace_ == NULL)
1590 nlen = strlen (namespace_);
1592 qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_info_cmp);
1594 /* Hash the folders. */
1595 hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1596 for (i = 0; i < folders->len; i++) {
1597 fi = folders->pdata[i];
1598 g_hash_table_insert (hash, g_strdup (fi->full_name), fi);
1601 /* Now find parents. */
1602 for (i = 0; i < folders->len; i++) {
1603 fi = folders->pdata[i];
1604 if (!strncmp (namespace_, fi->full_name, nlen)
1605 && (p = strrchr (fi->full_name + nlen, separator))) {
1606 pname = g_strndup (fi->full_name, p - fi->full_name);
1607 pfi = g_hash_table_lookup (hash, pname);
1611 /* we are missing a folder in the heirarchy so
1612 * create a fake folder node */
1614 pfi = camel_folder_info_new ();
1617 pfi->display_name = strrchr (pname, separator);
1618 if (pfi->display_name != NULL)
1619 pfi->display_name = g_strdup (pfi->display_name + 1);
1621 pfi->display_name = g_strdup (pname);
1623 pfi->display_name = g_strdup (pname);
1625 pfi->full_name = g_strdup (pname);
1627 /* Since this is a "fake" folder
1628 * node, it is not selectable. */
1629 pfi->flags |= CAMEL_FOLDER_NOSELECT;
1631 g_hash_table_insert (hash, pname, pfi);
1632 g_ptr_array_add (folders, pfi);
1634 tail = (CamelFolderInfo *) &pfi->child;
1639 } else if (!top || !g_ascii_strcasecmp (fi->full_name, "Inbox"))
1642 g_hash_table_destroy (hash);
1644 /* Link together the top-level folders */
1646 for (i = 0; i < folders->len; i++) {
1647 fi = folders->pdata[i];
1650 fi->flags &= ~CAMEL_FOLDER_NOCHILDREN;
1652 if (fi->parent || fi == top)
1666 static CamelFolderInfo *
1667 folder_info_clone_rec (CamelFolderInfo *fi,
1668 CamelFolderInfo *parent)
1670 CamelFolderInfo *info;
1672 info = camel_folder_info_new ();
1673 info->parent = parent;
1674 info->full_name = g_strdup (fi->full_name);
1675 info->display_name = g_strdup (fi->display_name);
1676 info->unread = fi->unread;
1677 info->flags = fi->flags;
1680 info->next = folder_info_clone_rec (fi->next, parent);
1685 info->child = folder_info_clone_rec (fi->child, info);
1693 * camel_folder_info_clone:
1694 * @fi: a #CamelFolderInfo
1696 * Clones @fi recursively.
1698 * Returns: the cloned #CamelFolderInfo tree.
1701 camel_folder_info_clone (CamelFolderInfo *fi)
1706 return folder_info_clone_rec (fi, NULL);
1710 * camel_store_can_refresh_folder
1711 * @store: a #CamelStore
1712 * @info: a #CamelFolderInfo
1713 * @error: return location for a #GError, or %NULL
1715 * Returns if this folder (param info) should be checked for new mail or not.
1716 * It should not look into sub infos (info->child) or next infos, it should
1717 * return value only for the actual folder info.
1718 * Default behavior is that all Inbox folders are intended to be refreshed.
1720 * Returns: whether folder should be checked for new mails
1725 camel_store_can_refresh_folder (CamelStore *store,
1726 CamelFolderInfo *info,
1729 CamelStoreClass *class;
1731 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
1732 g_return_val_if_fail (info != NULL, FALSE);
1734 class = CAMEL_STORE_GET_CLASS (store);
1735 g_return_val_if_fail (class->can_refresh_folder != NULL, FALSE);
1737 return class->can_refresh_folder (store, info, error);
1742 * @store: a #CamelStore
1743 * @lock: lock type to lock
1745 * Locks @store's @lock. Unlock it with camel_store_unlock().
1750 camel_store_lock (CamelStore *store,
1751 CamelStoreLock lock)
1753 g_return_if_fail (CAMEL_IS_STORE (store));
1756 case CAMEL_STORE_FOLDER_LOCK:
1757 g_rec_mutex_lock (&store->priv->folder_lock);
1760 g_return_if_reached ();
1765 * camel_store_unlock:
1766 * @store: a #CamelStore
1767 * @lock: lock type to unlock
1769 * Unlocks @store's @lock, previously locked with camel_store_lock().
1774 camel_store_unlock (CamelStore *store,
1775 CamelStoreLock lock)
1777 g_return_if_fail (CAMEL_IS_STORE (store));
1780 case CAMEL_STORE_FOLDER_LOCK:
1781 g_rec_mutex_unlock (&store->priv->folder_lock);
1784 g_return_if_reached ();
1789 * camel_store_get_folder_sync:
1790 * @store: a #CamelStore
1791 * @folder_name: name of the folder to get
1792 * @flags: folder flags (create, save body index, etc)
1793 * @cancellable: optional #GCancellable object, or %NULL
1794 * @error: return location for a #GError, or %NULL
1796 * Gets a specific folder object from @store by name.
1798 * Returns: the requested #CamelFolder object, or %NULL on error
1803 camel_store_get_folder_sync (CamelStore *store,
1804 const gchar *folder_name,
1805 CamelStoreGetFolderFlags flags,
1806 GCancellable *cancellable,
1809 CamelStoreClass *class;
1810 CamelFolder *folder = NULL;
1812 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
1813 g_return_val_if_fail (folder_name != NULL, NULL);
1815 class = CAMEL_STORE_GET_CLASS (store);
1817 /* O_EXCL doesn't make sense if we aren't requesting
1818 * to also create the folder if it doesn't exist. */
1819 if (!(flags & CAMEL_STORE_FOLDER_CREATE))
1820 flags &= ~CAMEL_STORE_FOLDER_EXCL;
1822 /* Try cache first. */
1823 folder = camel_object_bag_reserve (store->folders, folder_name);
1824 if (folder != NULL && (flags & CAMEL_STORE_FOLDER_EXCL)) {
1826 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
1827 _("Cannot create folder '%s': folder exists"),
1829 camel_object_bag_abort (store->folders, folder_name);
1830 g_object_unref (folder);
1834 if (folder == NULL) {
1835 CamelVeeFolder *vjunk = NULL;
1836 CamelVeeFolder *vtrash = NULL;
1837 gboolean folder_name_is_vjunk;
1838 gboolean folder_name_is_vtrash;
1839 gboolean store_uses_vjunk;
1840 gboolean store_uses_vtrash;
1843 ((store->flags & CAMEL_STORE_VJUNK) != 0);
1845 ((store->flags & CAMEL_STORE_VTRASH) != 0);
1846 folder_name_is_vjunk =
1848 (strcmp (folder_name, CAMEL_VJUNK_NAME) == 0);
1849 folder_name_is_vtrash =
1850 store_uses_vtrash &&
1851 (strcmp (folder_name, CAMEL_VTRASH_NAME) == 0);
1853 if (flags & CAMEL_STORE_IS_MIGRATING) {
1854 if (folder_name_is_vtrash) {
1855 if (store->folders != NULL)
1856 camel_object_bag_abort (
1857 store->folders, folder_name);
1861 if (folder_name_is_vjunk) {
1862 if (store->folders != NULL)
1863 camel_object_bag_abort (
1864 store->folders, folder_name);
1869 camel_operation_push_message (
1870 cancellable, _("Opening folder '%s'"), folder_name);
1872 if (folder_name_is_vtrash) {
1873 folder = class->get_trash_folder_sync (
1874 store, cancellable, error);
1875 CAMEL_CHECK_GERROR (
1876 store, get_trash_folder_sync,
1877 folder != NULL, error);
1878 } else if (folder_name_is_vjunk) {
1879 folder = class->get_junk_folder_sync (
1880 store, cancellable, error);
1881 CAMEL_CHECK_GERROR (
1882 store, get_junk_folder_sync,
1883 folder != NULL, error);
1885 folder = class->get_folder_sync (
1886 store, folder_name, flags,
1887 cancellable, error);
1888 CAMEL_CHECK_GERROR (
1889 store, get_folder_sync,
1890 folder != NULL, error);
1892 if (folder != NULL && store_uses_vjunk)
1893 vjunk = camel_object_bag_get (
1894 store->folders, CAMEL_VJUNK_NAME);
1896 if (folder != NULL && store_uses_vtrash)
1897 vtrash = camel_object_bag_get (
1898 store->folders, CAMEL_VTRASH_NAME);
1901 /* Release the folder name reservation before adding the
1902 * folder to the virtual Junk and Trash folders, just to
1903 * reduce the chance of deadlock. */
1905 camel_object_bag_add (
1906 store->folders, folder_name, folder);
1908 camel_object_bag_abort (
1909 store->folders, folder_name);
1911 /* If this is a normal folder and the store uses a
1912 * virtual Junk folder, let the virtual Junk folder
1913 * track this folder. */
1914 if (vjunk != NULL) {
1915 camel_vee_folder_add_folder (vjunk, folder, NULL);
1916 g_object_unref (vjunk);
1919 /* If this is a normal folder and the store uses a
1920 * virtual Trash folder, let the virtual Trash folder
1921 * track this folder. */
1922 if (vtrash != NULL) {
1923 camel_vee_folder_add_folder (vtrash, folder, NULL);
1924 g_object_unref (vtrash);
1927 camel_operation_pop_message (cancellable);
1930 camel_store_folder_opened (store, folder);
1937 * camel_store_get_folder:
1938 * @store: a #CamelStore
1939 * @folder_name: name of the folder to get
1940 * @flags: folder flags (create, save body index, etc)
1941 * @io_priority: the I/O priority of the request
1942 * @cancellable: optional #GCancellable object, or %NULL
1943 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1944 * @user_data: data to pass to the callback function
1946 * Asynchronously gets a specific folder object from @store by name.
1948 * When the operation is finished, @callback will be called. You can then
1949 * call camel_store_get_folder_finish() to get the result of the operation.
1954 camel_store_get_folder (CamelStore *store,
1955 const gchar *folder_name,
1956 CamelStoreGetFolderFlags flags,
1958 GCancellable *cancellable,
1959 GAsyncReadyCallback callback,
1962 CamelStoreClass *class;
1964 g_return_if_fail (CAMEL_IS_STORE (store));
1965 g_return_if_fail (folder_name != NULL);
1967 class = CAMEL_STORE_GET_CLASS (store);
1968 g_return_if_fail (class->get_folder != NULL);
1971 store, folder_name, flags, io_priority,
1972 cancellable, callback, user_data);
1976 * camel_store_get_folder_finish:
1977 * @store: a #CamelStore
1978 * @result: a #GAsyncResult
1979 * @error: return location for a #GError, or %NULL
1981 * Finishes the operation started with camel_store_get_folder().
1983 * Returns: the requested #CamelFolder object, or %NULL on error
1988 camel_store_get_folder_finish (CamelStore *store,
1989 GAsyncResult *result,
1992 CamelStoreClass *class;
1994 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
1995 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
1997 class = CAMEL_STORE_GET_CLASS (store);
1998 g_return_val_if_fail (class->get_folder_finish != NULL, NULL);
2000 return class->get_folder_finish (store, result, error);
2004 * camel_store_get_folder_info_sync:
2005 * @store: a #CamelStore
2006 * @top: the name of the folder to start from
2007 * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
2008 * @cancellable: optional #GCancellable object, or %NULL
2009 * @error: return location for a #GError, or %NULL
2011 * This fetches information about the folder structure of @store,
2012 * starting with @top, and returns a tree of #CamelFolderInfo
2013 * structures. If @flags includes %CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
2014 * only subscribed folders will be listed. If the store doesn't support
2015 * subscriptions, then it will list all folders. If @flags includes
2016 * %CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include
2017 * all levels of hierarchy below @top. If not, it will only include
2018 * the immediate subfolders of @top. If @flags includes
2019 * %CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of
2020 * some or all of the structures may be set to %-1, if the store cannot
2021 * determine that information quickly. If @flags includes
2022 * %CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual
2023 * folders (such as vTrash or vJunk).
2025 * The returned #CamelFolderInfo tree should be freed with
2026 * camel_store_free_folder_info().
2028 * The CAMEL_STORE_FOLDER_INFO_FAST flag should be considered
2029 * deprecated; most backends will behave the same whether it is
2030 * supplied or not. The only guaranteed way to get updated folder
2031 * counts is to both open the folder and invoke refresh_info() it.
2033 * Returns: a #CamelFolderInfo tree, or %NULL on error
2038 camel_store_get_folder_info_sync (CamelStore *store,
2040 CamelStoreGetFolderInfoFlags flags,
2041 GCancellable *cancellable,
2044 CamelStoreClass *class;
2045 CamelFolderInfo *info;
2048 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2050 class = CAMEL_STORE_GET_CLASS (store);
2051 g_return_val_if_fail (class->get_folder_info_sync != NULL, NULL);
2053 name = camel_service_get_name (CAMEL_SERVICE (store), TRUE);
2054 camel_operation_push_message (
2055 cancellable, _("Scanning folders in '%s'"), name);
2058 info = class->get_folder_info_sync (
2059 store, top, flags, cancellable, error);
2060 if (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED))
2061 CAMEL_CHECK_GERROR (
2062 store, get_folder_info_sync, info != NULL, error);
2064 if (info && (top == NULL || *top == '\0') && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) {
2065 if (store->flags & CAMEL_STORE_VTRASH)
2066 /* the name of the Trash folder, used for deleted messages */
2067 add_special_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL | CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_VTRASH | CAMEL_FOLDER_TYPE_TRASH);
2068 if (store->flags & CAMEL_STORE_VJUNK)
2069 /* the name of the Junk folder, used for spam messages */
2070 add_special_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL | CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_VTRASH | CAMEL_FOLDER_TYPE_JUNK);
2071 } else if (!info && top && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) {
2072 CamelFolderInfo *root_info = NULL;
2074 if ((store->flags & CAMEL_STORE_VTRASH) != 0 && g_str_equal (top, CAMEL_VTRASH_NAME)) {
2075 root_info = class->get_folder_info_sync (store, NULL, flags & (~CAMEL_STORE_FOLDER_INFO_RECURSIVE), cancellable, error);
2077 add_special_info (store, root_info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL | CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_VTRASH | CAMEL_FOLDER_TYPE_TRASH);
2078 } else if ((store->flags & CAMEL_STORE_VJUNK) != 0 && g_str_equal (top, CAMEL_VJUNK_NAME)) {
2079 root_info = class->get_folder_info_sync (store, NULL, flags & (~CAMEL_STORE_FOLDER_INFO_RECURSIVE), cancellable, error);
2081 add_special_info (store, root_info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL | CAMEL_FOLDER_SYSTEM | CAMEL_FOLDER_VTRASH | CAMEL_FOLDER_TYPE_JUNK);
2085 info = root_info->next;
2086 root_info->next = NULL;
2088 info->parent = NULL;
2090 camel_store_free_folder_info (store, root_info);
2094 camel_operation_pop_message (cancellable);
2096 if (camel_debug_start ("store:folder_info")) {
2099 uid = camel_service_get_uid (CAMEL_SERVICE (store));
2101 "Get folder info(%p:%s, '%s') =\n",
2102 (gpointer) store, uid, top ? top : "<null>");
2111 * camel_store_get_folder_info:
2112 * @store: a #CamelStore
2113 * @top: the name of the folder to start from
2114 * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
2115 * @io_priority: the I/O priority of the request
2116 * @cancellable: optional #GCancellable object, or %NULL
2117 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2118 * @user_data: data to pass to the callback function
2120 * Asynchronously fetches information about the folder structure of @store,
2121 * starting with @top. For details of the behavior, see
2122 * camel_store_get_folder_info_sync().
2124 * When the operation is finished, @callback will be called. You can
2125 * then call camel_store_get_folder_info_finish() to get the result of
2131 camel_store_get_folder_info (CamelStore *store,
2133 CamelStoreGetFolderInfoFlags flags,
2135 GCancellable *cancellable,
2136 GAsyncReadyCallback callback,
2139 CamelStoreClass *class;
2141 g_return_if_fail (CAMEL_IS_STORE (store));
2143 class = CAMEL_STORE_GET_CLASS (store);
2144 g_return_if_fail (class->get_folder_info != NULL);
2146 class->get_folder_info (
2147 store, top, flags, io_priority,
2148 cancellable, callback, user_data);
2152 * camel_store_get_folder_info_finish:
2153 * @store: a #CamelStore
2154 * @result: a #GAsyncResult
2155 * @error: return location for a #GError, or %NULL
2157 * Finishes the operation started with camel_store_get_folder_info().
2158 * The returned #CamelFolderInfo tree should be freed with
2159 * camel_store_free_folder_info().
2161 * Returns: a #CamelFolderInfo tree, or %NULL on error
2166 camel_store_get_folder_info_finish (CamelStore *store,
2167 GAsyncResult *result,
2170 CamelStoreClass *class;
2172 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2173 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2175 class = CAMEL_STORE_GET_CLASS (store);
2176 g_return_val_if_fail (class->get_folder_info_finish != NULL, NULL);
2178 return class->get_folder_info_finish (store, result, error);
2182 * camel_store_get_inbox_folder_sync:
2183 * @store: a #CamelStore
2184 * @cancellable: optional #GCancellable object, or %NULL
2185 * @error: return location for a #GError, or %NULL
2187 * Gets the folder in @store into which new mail is delivered.
2189 * Returns: the inbox folder for @store, or %NULL on error or if no such
2195 camel_store_get_inbox_folder_sync (CamelStore *store,
2196 GCancellable *cancellable,
2199 CamelStoreClass *class;
2200 CamelFolder *folder;
2202 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2204 class = CAMEL_STORE_GET_CLASS (store);
2205 g_return_val_if_fail (class->get_inbox_folder_sync != NULL, NULL);
2207 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2209 /* Check for cancellation after locking. */
2210 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2211 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2215 folder = class->get_inbox_folder_sync (store, cancellable, error);
2216 CAMEL_CHECK_GERROR (
2217 store, get_inbox_folder_sync, folder != NULL, error);
2219 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2225 * camel_store_get_inbox_folder:
2226 * @store: a #CamelStore
2227 * @io_priority: the I/O priority of the request
2228 * @cancellable: optional #GCancellable object, or %NULL
2229 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2230 * @user_data: data to pass to the callback function
2232 * Asynchronously gets the folder in @store into which new mail is delivered.
2234 * When the operation is finished, @callback will be called. You can
2235 * then call camel_store_get_inbox_folder_finish() to get the result of
2241 camel_store_get_inbox_folder (CamelStore *store,
2243 GCancellable *cancellable,
2244 GAsyncReadyCallback callback,
2247 CamelStoreClass *class;
2249 g_return_if_fail (CAMEL_IS_STORE (store));
2251 class = CAMEL_STORE_GET_CLASS (store);
2252 g_return_if_fail (class->get_inbox_folder != NULL);
2254 class->get_inbox_folder (
2255 store, io_priority, cancellable, callback, user_data);
2259 * camel_store_get_inbox_folder_finish:
2260 * @store: a #CamelStore
2261 * @result: a #GAsyncResult
2262 * @error: return location for a #GError, or %NULL
2264 * Finishes the operation started with camel_store_get_inbox_folder().
2266 * Returns: the inbox folder for @store, or %NULL on error or if no such
2272 camel_store_get_inbox_folder_finish (CamelStore *store,
2273 GAsyncResult *result,
2276 CamelStoreClass *class;
2278 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2279 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2281 class = CAMEL_STORE_GET_CLASS (store);
2282 g_return_val_if_fail (class->get_inbox_folder_finish != NULL, NULL);
2284 return class->get_inbox_folder_finish (store, result, error);
2288 * camel_store_get_junk_folder_sync:
2289 * @store: a #CamelStore
2290 * @cancellable: optional #GCancellable object, or %NULL
2291 * @error: return location for a #GError, or %NULL
2293 * Gets the folder in @store into which junk is delivered.
2295 * Returns: the junk folder for @store, or %NULL on error or if no such
2301 camel_store_get_junk_folder_sync (CamelStore *store,
2302 GCancellable *cancellable,
2305 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2307 if ((store->flags & CAMEL_STORE_VJUNK) == 0) {
2308 CamelStoreClass *class;
2309 CamelFolder *folder;
2311 class = CAMEL_STORE_GET_CLASS (store);
2312 g_return_val_if_fail (class->get_junk_folder_sync != NULL, NULL);
2314 folder = class->get_junk_folder_sync (store, cancellable, error);
2315 CAMEL_CHECK_GERROR (
2316 store, get_junk_folder_sync, folder != NULL, error);
2321 return camel_store_get_folder_sync (
2322 store, CAMEL_VJUNK_NAME, 0, cancellable, error);
2326 * camel_store_get_junk_folder:
2327 * @store: a #CamelStore
2328 * @io_priority: the I/O priority of the request
2329 * @cancellable: optional #GCancellable object, or %NULL
2330 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2331 * @user_data: data to pass to the callback function
2333 * Asynchronously gets the folder in @store into which junk is delivered.
2335 * When the operation is finished, @callback will be called. You can
2336 * then call camel_store_get_junk_folder_finish() to get the result of
2342 camel_store_get_junk_folder (CamelStore *store,
2344 GCancellable *cancellable,
2345 GAsyncReadyCallback callback,
2348 CamelStoreClass *class;
2350 g_return_if_fail (CAMEL_IS_STORE (store));
2352 class = CAMEL_STORE_GET_CLASS (store);
2353 g_return_if_fail (class->get_junk_folder != NULL);
2355 class->get_junk_folder (
2356 store, io_priority, cancellable, callback, user_data);
2360 * camel_store_get_junk_folder_finish:
2361 * @store: a #CamelStore
2362 * @result: a #GAsyncResult
2363 * @error: return location for a #GError, or %NULL
2365 * Finishes the operation started with camel_store_get_junk_folder().
2367 * Returns: the junk folder for @store, or %NULL on error or if no such
2373 camel_store_get_junk_folder_finish (CamelStore *store,
2374 GAsyncResult *result,
2377 CamelStoreClass *class;
2379 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2380 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2382 class = CAMEL_STORE_GET_CLASS (store);
2383 g_return_val_if_fail (class->get_junk_folder_finish != NULL, NULL);
2385 return class->get_junk_folder_finish (store, result, error);
2389 * camel_store_get_trash_folder_sync:
2390 * @store: a #CamelStore
2391 * @cancellable: optional #GCancellable object, or %NULL
2392 * @error: return location for a #GError, or %NULL
2394 * Gets the folder in @store into which trash is delivered.
2396 * Returns: the trash folder for @store, or %NULL on error or if no such
2402 camel_store_get_trash_folder_sync (CamelStore *store,
2403 GCancellable *cancellable,
2406 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2408 if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
2409 CamelStoreClass *class;
2410 CamelFolder *folder;
2412 class = CAMEL_STORE_GET_CLASS (store);
2413 g_return_val_if_fail (class->get_trash_folder_sync != NULL, NULL);
2415 folder = class->get_trash_folder_sync (
2416 store, cancellable, error);
2417 CAMEL_CHECK_GERROR (
2418 store, get_trash_folder_sync, folder != NULL, error);
2423 return camel_store_get_folder_sync (
2424 store, CAMEL_VTRASH_NAME, 0, cancellable, error);
2428 * camel_store_get_trash_folder:
2429 * @store: a #CamelStore
2430 * @io_priority: the I/O priority of the request
2431 * @cancellable: optional #GCancellable object, or %NULL
2432 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2433 * @user_data: data to pass to the callback function
2435 * Asynchronously gets the folder in @store into which trash is delivered.
2437 * When the operation is finished, @callback will be called. You can
2438 * then call camel_store_get_trash_folder_finish() to get the result of
2444 camel_store_get_trash_folder (CamelStore *store,
2446 GCancellable *cancellable,
2447 GAsyncReadyCallback callback,
2450 CamelStoreClass *class;
2452 g_return_if_fail (CAMEL_IS_STORE (store));
2454 class = CAMEL_STORE_GET_CLASS (store);
2455 g_return_if_fail (class->get_trash_folder != NULL);
2457 class->get_trash_folder (
2458 store, io_priority, cancellable, callback, user_data);
2462 * camel_store_get_trash_folder_finish:
2463 * @store: a #CamelStore
2464 * @result: a #GAsyncResult
2465 * @error: return location for a #GError, or %NULL
2467 * Finishes the operation started with camel_store_get_trash_folder().
2469 * Returns: the trash folder for @store, or %NULL on error or if no such
2475 camel_store_get_trash_folder_finish (CamelStore *store,
2476 GAsyncResult *result,
2479 CamelStoreClass *class;
2481 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2482 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2484 class = CAMEL_STORE_GET_CLASS (store);
2485 g_return_val_if_fail (class->get_trash_folder_finish != NULL, NULL);
2487 return class->get_trash_folder_finish (store, result, error);
2491 * camel_store_create_folder_sync:
2492 * @store: a #CamelStore
2493 * @parent_name: name of the new folder's parent, or %NULL
2494 * @folder_name: name of the folder to create
2495 * @cancellable: optional #GCancellable object, or %NULL
2496 * @error: return location for a #GError, or %NULL
2498 * Creates a new folder as a child of an existing folder.
2499 * @parent_name can be %NULL to create a new top-level folder.
2500 * The returned #CamelFolderInfo struct should be freed with
2501 * camel_store_free_folder_info().
2503 * Returns: info about the created folder, or %NULL on error
2508 camel_store_create_folder_sync (CamelStore *store,
2509 const gchar *parent_name,
2510 const gchar *folder_name,
2511 GCancellable *cancellable,
2514 CamelStoreClass *class;
2515 CamelFolderInfo *fi;
2517 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2518 g_return_val_if_fail (folder_name != NULL, NULL);
2520 class = CAMEL_STORE_GET_CLASS (store);
2521 g_return_val_if_fail (class->create_folder_sync != NULL, NULL);
2523 if ((parent_name == NULL || parent_name[0] == 0)
2524 && (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
2525 || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0))) {
2527 error, CAMEL_STORE_ERROR,
2528 CAMEL_STORE_ERROR_INVALID,
2529 _("Cannot create folder: %s: folder exists"),
2534 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2536 /* Check for cancellation after locking. */
2537 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2538 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2542 camel_operation_push_message (
2543 cancellable, _("Creating folder '%s'"), folder_name);
2545 fi = class->create_folder_sync (
2546 store, parent_name, folder_name, cancellable, error);
2547 CAMEL_CHECK_GERROR (store, create_folder_sync, fi != NULL, error);
2549 camel_operation_pop_message (cancellable);
2551 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2557 * camel_store_create_folder:
2558 * @store: a #CamelStore
2559 * @parent_name: name of the new folder's parent, or %NULL
2560 * @folder_name: name of the folder to create
2561 * @io_priority: the I/O priority of the request
2562 * @cancellable: optional #GCancellable object, or %NULL
2563 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2564 * @user_data: data to pass to the callback function
2566 * Asynchronously creates a new folder as a child of an existing folder.
2567 * @parent_name can be %NULL to create a new top-level folder.
2569 * When the operation is finished, @callback will be called. You can then
2570 * call camel_store_create_folder_finish() to get the result of the operation.
2575 camel_store_create_folder (CamelStore *store,
2576 const gchar *parent_name,
2577 const gchar *folder_name,
2579 GCancellable *cancellable,
2580 GAsyncReadyCallback callback,
2583 CamelStoreClass *class;
2585 g_return_if_fail (CAMEL_IS_STORE (store));
2586 g_return_if_fail (folder_name != NULL);
2588 class = CAMEL_STORE_GET_CLASS (store);
2589 g_return_if_fail (class->create_folder != NULL);
2591 class->create_folder (
2592 store, parent_name, folder_name, io_priority,
2593 cancellable, callback, user_data);
2597 * camel_store_create_folder_finish:
2598 * @store: a #CamelStore
2599 * @result: a #GAsyncResult
2600 * @error: return location for a #GError, or %NULL
2602 * Finishes the operation started with camel_store_create_folder().
2603 * The returned #CamelFolderInfo struct should be freed with
2604 * camel_store_free_folder_info().
2606 * Returns: info about the created folder, or %NULL on error
2611 camel_store_create_folder_finish (CamelStore *store,
2612 GAsyncResult *result,
2615 CamelStoreClass *class;
2617 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2618 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2620 class = CAMEL_STORE_GET_CLASS (store);
2621 g_return_val_if_fail (class->create_folder_finish != NULL, NULL);
2623 return class->create_folder_finish (store, result, error);
2627 * camel_store_delete_folder_sync:
2628 * @store: a #CamelStore
2629 * @folder_name: name of the folder to delete
2630 * @cancellable: optional #GCancellable object, or %NULL
2631 * @error: return location for a #GError, or %NULL
2633 * Deletes the folder described by @folder_name. The folder must be empty.
2635 * Returns: %TRUE on success, %FALSE on failure
2640 camel_store_delete_folder_sync (CamelStore *store,
2641 const gchar *folder_name,
2642 GCancellable *cancellable,
2645 CamelStoreClass *class;
2647 GError *local_error = NULL, **check_error = NULL;
2649 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2650 g_return_val_if_fail (folder_name != NULL, FALSE);
2652 class = CAMEL_STORE_GET_CLASS (store);
2653 g_return_val_if_fail (class->delete_folder_sync != NULL, FALSE);
2655 /* TODO: should probably be a parameter/bit on the storeinfo */
2656 if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
2657 || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0)) {
2659 error, CAMEL_STORE_ERROR,
2660 CAMEL_STORE_ERROR_NO_FOLDER,
2661 _("Cannot delete folder: %s: Invalid operation"),
2666 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2668 /* Check for cancellation after locking. */
2669 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2670 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2674 success = class->delete_folder_sync (
2675 store, folder_name, cancellable, &local_error);
2677 check_error = &local_error;
2678 CAMEL_CHECK_GERROR (store, delete_folder_sync, success, check_error);
2680 /* ignore 'no such table' errors */
2681 if (local_error != NULL &&
2682 g_ascii_strncasecmp (local_error->message, "no such table", 13) == 0)
2683 g_clear_error (&local_error);
2685 if (local_error == NULL)
2686 cs_delete_cached_folder (store, folder_name);
2688 g_propagate_error (error, local_error);
2690 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2696 * camel_store_delete_folder:
2697 * @store: a #CamelStore
2698 * @folder_name: name of the folder to delete
2699 * @io_priority: the I/O priority of the request
2700 * @cancellable: optional #GCancellable object, or %NULL
2701 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2702 * @user_data: data to pass to the callback function
2704 * Asynchronously deletes the folder described by @folder_name. The
2705 * folder must be empty.
2707 * When the operation is finished, @callback will be called. You can then
2708 * call camel_store_delete_folder_finish() to get the result of the operation.
2713 camel_store_delete_folder (CamelStore *store,
2714 const gchar *folder_name,
2716 GCancellable *cancellable,
2717 GAsyncReadyCallback callback,
2720 CamelStoreClass *class;
2722 g_return_if_fail (CAMEL_IS_STORE (store));
2723 g_return_if_fail (folder_name != NULL);
2725 class = CAMEL_STORE_GET_CLASS (store);
2726 g_return_if_fail (class->delete_folder != NULL);
2728 class->delete_folder (
2729 store, folder_name, io_priority,
2730 cancellable, callback, user_data);
2734 * camel_store_delete_folder_finish:
2735 * @store: a #CamelStore
2736 * @result: a #GAsyncResult
2737 * @error: return location for a #GError, or %NULL
2739 * Finishes the operation started with camel_store_delete_folder().
2741 * Returns: %TRUE on success, %FALSE on error
2746 camel_store_delete_folder_finish (CamelStore *store,
2747 GAsyncResult *result,
2750 CamelStoreClass *class;
2752 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2753 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2755 class = CAMEL_STORE_GET_CLASS (store);
2756 g_return_val_if_fail (class->delete_folder_finish != NULL, FALSE);
2758 return class->delete_folder_finish (store, result, error);
2762 * camel_store_rename_folder_sync:
2763 * @store: a #CamelStore
2764 * @old_name: the current name of the folder
2765 * @new_name: the new name of the folder
2766 * @cancellable: optional #GCancellable object, or %NULL
2767 * @error: return location for a #GError, or %NULL
2769 * Renames the folder described by @old_name to @new_name.
2771 * Returns: %TRUE on success, %FALSE on error
2776 camel_store_rename_folder_sync (CamelStore *store,
2777 const gchar *old_namein,
2778 const gchar *new_name,
2779 GCancellable *cancellable,
2782 CamelStoreClass *class;
2783 CamelFolder *folder;
2784 gint i, oldlen, namelen;
2785 GPtrArray *folders = NULL;
2789 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2790 g_return_val_if_fail (old_namein != NULL, FALSE);
2791 g_return_val_if_fail (new_name != NULL, FALSE);
2793 class = CAMEL_STORE_GET_CLASS (store);
2794 g_return_val_if_fail (class->rename_folder_sync != NULL, FALSE);
2796 if (strcmp (old_namein, new_name) == 0)
2799 if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (old_namein, CAMEL_VTRASH_NAME) == 0)
2800 || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (old_namein, CAMEL_VJUNK_NAME) == 0)) {
2802 error, CAMEL_STORE_ERROR,
2803 CAMEL_STORE_ERROR_NO_FOLDER,
2804 _("Cannot rename folder: %s: Invalid operation"),
2809 /* need to save this, since old_namein might be folder->full_name, which could go away */
2810 old_name = g_strdup (old_namein);
2811 oldlen = strlen (old_name);
2813 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2815 /* Check for cancellation after locking. */
2816 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2817 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2821 /* If the folder is open (or any subfolders of the open folder)
2822 * We need to rename them atomically with renaming the actual
2824 folders = camel_object_bag_list (store->folders);
2825 for (i = 0; folders && i < folders->len; i++) {
2826 const gchar *full_name;
2828 folder = folders->pdata[i];
2829 full_name = camel_folder_get_full_name (folder);
2831 namelen = strlen (full_name);
2832 if ((namelen == oldlen &&
2833 strcmp (full_name, old_name) == 0)
2834 || ((namelen > oldlen)
2835 && strncmp (full_name, old_name, oldlen) == 0
2836 && full_name[oldlen] == '/')) {
2837 camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
2839 g_ptr_array_remove_index_fast (folders, i);
2841 g_object_unref (folder);
2845 /* Now try the real rename (will emit renamed signal) */
2846 success = class->rename_folder_sync (
2847 store, old_name, new_name, cancellable, error);
2848 CAMEL_CHECK_GERROR (store, rename_folder_sync, success, error);
2850 /* If it worked, update all open folders/unlock them */
2853 CamelStoreGetFolderInfoFlags flags;
2854 CamelFolderInfo *folder_info;
2856 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
2858 for (i = 0; i < folders->len; i++) {
2859 const gchar *full_name;
2862 folder = folders->pdata[i];
2863 full_name = camel_folder_get_full_name (folder);
2865 new = g_strdup_printf ("%s%s", new_name, full_name + strlen (old_name));
2866 camel_object_bag_rekey (store->folders, folder, new);
2867 camel_folder_rename (folder, new);
2870 camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
2871 g_object_unref (folder);
2874 /* Emit renamed signal */
2875 if (CAMEL_IS_SUBSCRIBABLE (store))
2876 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
2878 folder_info = class->get_folder_info_sync (
2879 store, new_name, flags, cancellable, error);
2880 CAMEL_CHECK_GERROR (store, get_folder_info, folder_info != NULL, error);
2882 if (folder_info != NULL) {
2883 camel_store_folder_renamed (store, old_name, folder_info);
2884 class->free_folder_info (store, folder_info);
2887 /* Failed, just unlock our folders for re-use */
2888 for (i = 0; i < folders->len; i++) {
2889 folder = folders->pdata[i];
2890 camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
2891 g_object_unref (folder);
2896 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2898 g_ptr_array_free (folders, TRUE);
2905 * camel_store_rename_folder:
2906 * @store: a #CamelStore
2907 * @old_name: the current name of the folder
2908 * @new_name: the new name of the folder
2909 * @io_priority: the I/O priority of the request
2910 * @cancellable: optional #GCancellable object, or %NULL
2911 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2912 * @user_data: data to pass to the callback function
2914 * Asynchronously renames the folder described by @old_name to @new_name.
2916 * When the operation is finished, @callback will be called. You can then
2917 * call camel_store_rename_folder_finish() to get the result of the operation.
2922 camel_store_rename_folder (CamelStore *store,
2923 const gchar *old_name,
2924 const gchar *new_name,
2926 GCancellable *cancellable,
2927 GAsyncReadyCallback callback,
2930 CamelStoreClass *class;
2932 g_return_if_fail (CAMEL_IS_STORE (store));
2933 g_return_if_fail (old_name != NULL);
2934 g_return_if_fail (new_name != NULL);
2936 class = CAMEL_STORE_GET_CLASS (store);
2937 g_return_if_fail (class->rename_folder != NULL);
2939 class->rename_folder (
2940 store, old_name, new_name, io_priority,
2941 cancellable, callback, user_data);
2945 * camel_store_rename_folder_finish:
2946 * @store: a #CamelStore
2947 * @result: a #GAsyncResult
2948 * @error: return location for a #GError, or %NULL
2950 * Finishes the operation started with camel_store_rename_folder().
2952 * Returns: %TRUE on success, %FALSE on error
2957 camel_store_rename_folder_finish (CamelStore *store,
2958 GAsyncResult *result,
2961 CamelStoreClass *class;
2963 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2964 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2966 class = CAMEL_STORE_GET_CLASS (store);
2967 g_return_val_if_fail (class->rename_folder_finish != NULL, FALSE);
2969 return class->rename_folder_finish (store, result, error);
2973 * camel_store_synchronize_sync:
2974 * @store: a #CamelStore
2975 * @expunge: whether to expunge after synchronizing
2976 * @cancellable: optional #GCancellable object, or %NULL
2977 * @error: return location for a #GError, or %NULL
2979 * Synchronizes any changes that have been made to @store and its folders
2980 * with the real store.
2982 * Returns: %TRUE on success, %FALSE on error
2987 camel_store_synchronize_sync (CamelStore *store,
2989 GCancellable *cancellable,
2992 CamelStoreClass *class;
2995 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2997 class = CAMEL_STORE_GET_CLASS (store);
2998 g_return_val_if_fail (class->synchronize_sync != NULL, FALSE);
3000 success = class->synchronize_sync (store, expunge, cancellable, error);
3001 CAMEL_CHECK_GERROR (store, synchronize_sync, success, error);
3007 * camel_store_synchronize:
3008 * @store: a #CamelStore
3009 * @expunge: whether to expunge after synchronizing
3010 * @io_priority: the I/O priority of the request
3011 * @cancellable: optional #GCancellable object, or %NULL
3012 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3013 * @user_data: data to pass to the callback function
3015 * Synchronizes any changes that have been made to @store and its folders
3016 * with the real store asynchronously.
3018 * When the operation is finished, @callback will be called. You can then
3019 * call camel_store_synchronize_finish() to get the result of the operation.
3024 camel_store_synchronize (CamelStore *store,
3027 GCancellable *cancellable,
3028 GAsyncReadyCallback callback,
3031 CamelStoreClass *class;
3033 g_return_if_fail (CAMEL_IS_STORE (store));
3035 class = CAMEL_STORE_GET_CLASS (store);
3036 g_return_if_fail (class->synchronize != NULL);
3038 class->synchronize (
3039 store, expunge, io_priority,
3040 cancellable, callback, user_data);
3044 * camel_store_synchronize_finish:
3045 * @store: a #CamelStore
3046 * @result: a #GAsyncResult
3047 * @error: return location for a #GError, or %NULL
3049 * Finishes the operation started with camel_store_synchronize().
3051 * Returns: %TRUE on success, %FALSE on error
3056 camel_store_synchronize_finish (CamelStore *store,
3057 GAsyncResult *result,
3060 CamelStoreClass *class;
3062 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
3063 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3065 class = CAMEL_STORE_GET_CLASS (store);
3066 g_return_val_if_fail (class->synchronize_finish != NULL, FALSE);
3068 return class->synchronize_finish (store, result, error);
3072 * camel_store_noop_sync:
3073 * @store: a #CamelStore
3074 * @cancellable: optional #GCancellable object, or %NULL
3075 * @error: return location for a #GError, or %NULL
3077 * Pings @store so its connection doesn't time out.
3079 * Returns: %TRUE on success, %FALSE on error
3084 camel_store_noop_sync (CamelStore *store,
3085 GCancellable *cancellable,
3088 CamelStoreClass *class;
3091 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
3093 class = CAMEL_STORE_GET_CLASS (store);
3094 g_return_val_if_fail (class->noop_sync != NULL, FALSE);
3096 success = class->noop_sync (store, cancellable, error);
3097 CAMEL_CHECK_GERROR (store, noop_sync, success, error);
3104 * @store: a #CamelStore
3105 * @io_priority: the I/O priority of the request
3106 * @cancellable: optional #GCancellable object, or %NULL
3107 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3108 * @user_data: data to pass to the callback function
3110 * Pings @store asynchronously so its connection doesn't time out.
3112 * When the operation is finished, @callback will be called. You can then
3113 * call camel_store_noop_finish() to get the result of the operation.
3118 camel_store_noop (CamelStore *store,
3120 GCancellable *cancellable,
3121 GAsyncReadyCallback callback,
3124 CamelStoreClass *class;
3126 g_return_if_fail (CAMEL_IS_STORE (store));
3128 class = CAMEL_STORE_GET_CLASS (store);
3129 g_return_if_fail (class->noop != NULL);
3131 class->noop (store, io_priority, cancellable, callback, user_data);
3135 * camel_store_noop_finish:
3136 * @store: a #CamelStore
3137 * @result: a #GAsyncResult
3138 * @error: return location for a #GError, or %NULL
3140 * Finishes the operation started with camel_store_noop().
3142 * Returns: %TRUE on success, %FALSE on error
3147 camel_store_noop_finish (CamelStore *store,
3148 GAsyncResult *result,
3151 CamelStoreClass *class;
3153 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
3154 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3156 class = CAMEL_STORE_GET_CLASS (store);
3157 g_return_val_if_fail (class->noop_finish != NULL, FALSE);
3159 return class->noop_finish (store, result, error);