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 GStaticRecMutex 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_static_rec_mutex_free (&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->compare_folder_name != NULL);
291 store->folders = camel_object_bag_new (
292 class->hash_folder_name,
293 class->compare_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->compare_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_static_rec_mutex_init (&store->priv->folder_lock);
1248 camel_store_error_quark (void)
1250 static GQuark quark = 0;
1252 if (G_UNLIKELY (quark == 0)) {
1253 const gchar *string = "camel-store-error-quark";
1254 quark = g_quark_from_static_string (string);
1261 * camel_store_folder_created:
1262 * @store: a #CamelStore
1263 * @folder_info: information about the created folder
1265 * Emits the #CamelStore::folder-created signal from an idle source on
1266 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1268 * This function is only intended for Camel providers.
1273 camel_store_folder_created (CamelStore *store,
1274 CamelFolderInfo *folder_info)
1276 CamelSession *session;
1277 SignalData *signal_data;
1279 g_return_if_fail (CAMEL_IS_STORE (store));
1280 g_return_if_fail (folder_info != NULL);
1282 session = camel_service_get_session (CAMEL_SERVICE (store));
1284 signal_data = g_slice_new0 (SignalData);
1285 signal_data->store = g_object_ref (store);
1286 signal_data->folder_info = camel_folder_info_clone (folder_info);
1288 camel_session_idle_add (
1289 session, G_PRIORITY_DEFAULT_IDLE,
1290 store_emit_folder_created_cb,
1291 signal_data, (GDestroyNotify) signal_data_free);
1295 * camel_store_folder_deleted:
1296 * @store: a #CamelStore
1297 * @folder_info: information about the deleted folder
1299 * Emits the #CamelStore::folder-deleted signal from an idle source on
1300 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1302 * This function is only intended for Camel providers.
1307 camel_store_folder_deleted (CamelStore *store,
1308 CamelFolderInfo *folder_info)
1310 CamelSession *session;
1311 SignalData *signal_data;
1313 g_return_if_fail (CAMEL_IS_STORE (store));
1314 g_return_if_fail (folder_info != NULL);
1316 session = camel_service_get_session (CAMEL_SERVICE (store));
1318 signal_data = g_slice_new0 (SignalData);
1319 signal_data->store = g_object_ref (store);
1320 signal_data->folder_info = camel_folder_info_clone (folder_info);
1322 camel_session_idle_add (
1323 session, G_PRIORITY_DEFAULT_IDLE,
1324 store_emit_folder_deleted_cb,
1325 signal_data, (GDestroyNotify) signal_data_free);
1329 * camel_store_folder_opened:
1330 * @store: a #CamelStore
1331 * @folder: the #CamelFolder that was opened
1333 * Emits the #CamelStore::folder-opened signal from an idle source on
1334 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1336 * This function is only intended for Camel providers.
1341 camel_store_folder_opened (CamelStore *store,
1342 CamelFolder *folder)
1344 CamelSession *session;
1345 SignalData *signal_data;
1347 g_return_if_fail (CAMEL_IS_STORE (store));
1348 g_return_if_fail (CAMEL_IS_FOLDER (folder));
1350 session = camel_service_get_session (CAMEL_SERVICE (store));
1352 signal_data = g_slice_new0 (SignalData);
1353 signal_data->store = g_object_ref (store);
1354 signal_data->folder = g_object_ref (folder);
1356 camel_session_idle_add (
1357 session, G_PRIORITY_DEFAULT_IDLE,
1358 store_emit_folder_opened_cb,
1359 signal_data, (GDestroyNotify) signal_data_free);
1363 * camel_store_folder_renamed:
1364 * @store: a #CamelStore
1365 * @old_name: the old name of the folder
1366 * @folder_info: information about the renamed folder
1368 * Emits the #CamelStore::folder-renamed signal from an idle source on
1369 * the main loop. The idle source's priority is #G_PRIORITY_DEFAULT_IDLE.
1371 * This function is only intended for Camel providers.
1376 camel_store_folder_renamed (CamelStore *store,
1377 const gchar *old_name,
1378 CamelFolderInfo *folder_info)
1380 CamelSession *session;
1381 SignalData *signal_data;
1383 g_return_if_fail (CAMEL_IS_STORE (store));
1384 g_return_if_fail (old_name != NULL);
1385 g_return_if_fail (folder_info != NULL);
1387 session = camel_service_get_session (CAMEL_SERVICE (store));
1389 signal_data = g_slice_new0 (SignalData);
1390 signal_data->store = g_object_ref (store);
1391 signal_data->folder_info = camel_folder_info_clone (folder_info);
1392 signal_data->folder_name = g_strdup (old_name);
1394 camel_session_idle_add (
1395 session, G_PRIORITY_DEFAULT_IDLE,
1396 store_emit_folder_renamed_cb,
1397 signal_data, (GDestroyNotify) signal_data_free);
1401 add_special_info (CamelStore *store,
1402 CamelFolderInfo *info,
1404 const gchar *translated,
1405 gboolean unread_count,
1406 CamelFolderInfoFlags flags)
1408 CamelFolderInfo *fi, *vinfo, *parent;
1410 g_return_if_fail (CAMEL_IS_STORE (store));
1411 g_return_if_fail (info != NULL);
1414 for (fi = info; fi; fi = fi->next) {
1415 if (!strcmp (fi->full_name, name))
1421 /* We're going to replace the physical Trash/Junk
1422 * folder with our vTrash/vJunk folder. */
1424 g_free (vinfo->full_name);
1425 g_free (vinfo->display_name);
1427 /* There wasn't a Trash/Junk folder so create a new
1429 vinfo = camel_folder_info_new ();
1431 g_assert (parent != NULL);
1434 CAMEL_FOLDER_NOINFERIORS |
1435 CAMEL_FOLDER_SUBSCRIBED;
1437 /* link it into the right spot */
1438 vinfo->next = parent->next;
1439 parent->next = vinfo;
1442 /* Fill in the new fields */
1443 vinfo->flags |= flags;
1444 vinfo->full_name = g_strdup (name);
1445 vinfo->display_name = g_strdup (translated);
1452 dump_fi (CamelFolderInfo *fi,
1457 s = g_alloca (depth + 1);
1458 memset (s, ' ', depth);
1462 printf("%sfull_name: %s\n", s, fi->full_name);
1463 printf("%sflags: %08x\n", s, fi->flags);
1464 dump_fi (fi->child, depth + 2);
1470 * camel_store_free_folder_info:
1471 * @store: a #CamelStore
1472 * @fi: a #CamelFolderInfo as gotten via camel_store_get_folder_info()
1474 * Frees the data returned by camel_store_get_folder_info(). If @fi is %NULL,
1475 * nothing is done, the routine simply returns.
1478 camel_store_free_folder_info (CamelStore *store,
1479 CamelFolderInfo *fi)
1481 CamelStoreClass *class;
1483 g_return_if_fail (CAMEL_IS_STORE (store));
1488 class = CAMEL_STORE_GET_CLASS (store);
1489 g_return_if_fail (class->free_folder_info != NULL);
1491 class->free_folder_info (store, fi);
1495 * camel_store_free_folder_info_full:
1496 * @store: a #CamelStore
1497 * @fi: a #CamelFolderInfo as gotten via camel_store_get_folder_info()
1499 * An implementation for #CamelStore::free_folder_info. Frees all
1503 camel_store_free_folder_info_full (CamelStore *store,
1504 CamelFolderInfo *fi)
1506 camel_folder_info_free (fi);
1510 * camel_store_free_folder_info_nop:
1511 * @store: a #CamelStore
1512 * @fi: a #CamelFolderInfo as gotten via camel_store_get_folder_info()
1514 * An implementation for #CamelStore::free_folder_info. Does nothing.
1517 camel_store_free_folder_info_nop (CamelStore *store,
1518 CamelFolderInfo *fi)
1524 * camel_folder_info_free:
1525 * @fi: a #CamelFolderInfo
1530 camel_folder_info_free (CamelFolderInfo *fi)
1533 camel_folder_info_free (fi->next);
1534 camel_folder_info_free (fi->child);
1535 g_free (fi->full_name);
1536 g_free (fi->display_name);
1537 g_slice_free (CamelFolderInfo, fi);
1542 * camel_folder_info_new:
1544 * Allocates a new #CamelFolderInfo instance. Free it with
1545 * camel_folder_info_free().
1547 * Returns: a new #CamelFolderInfo instance
1552 camel_folder_info_new (void)
1554 return g_slice_new0 (CamelFolderInfo);
1558 folder_info_cmp (gconstpointer ap,
1561 const CamelFolderInfo *a = ((CamelFolderInfo **) ap)[0];
1562 const CamelFolderInfo *b = ((CamelFolderInfo **) bp)[0];
1564 return strcmp (a->full_name, b->full_name);
1568 * camel_folder_info_build:
1569 * @folders: an array of #CamelFolderInfo
1570 * @namespace: an ignorable prefix on the folder names
1571 * @separator: the hieararchy separator character
1572 * @short_names: %TRUE if the (short) name of a folder is the part after
1573 * the last @separator in the full name. %FALSE if it is the full name.
1575 * This takes an array of folders and attaches them together according
1576 * to the hierarchy described by their full_names and @separator. If
1577 * @namespace is non-%NULL, then it will be ignored as a full_name
1578 * prefix, for purposes of comparison. If necessary,
1579 * camel_folder_info_build() will create additional #CamelFolderInfo with
1580 * %NULL urls to fill in gaps in the tree. The value of @short_names
1581 * is used in constructing the names of these intermediate folders.
1583 * NOTE: This is deprected, do not use this.
1584 * FIXME: remove this/move it to imap, which is the only user of it now.
1586 * Returns: the top level of the tree of linked folder info.
1589 camel_folder_info_build (GPtrArray *folders,
1590 const gchar *namespace,
1592 gboolean short_names)
1594 CamelFolderInfo *fi, *pfi, *top = NULL, *tail = NULL;
1601 nlen = strlen (namespace);
1603 qsort (folders->pdata, folders->len, sizeof (folders->pdata[0]), folder_info_cmp);
1605 /* Hash the folders. */
1606 hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
1607 for (i = 0; i < folders->len; i++) {
1608 fi = folders->pdata[i];
1609 g_hash_table_insert (hash, g_strdup (fi->full_name), fi);
1612 /* Now find parents. */
1613 for (i = 0; i < folders->len; i++) {
1614 fi = folders->pdata[i];
1615 if (!strncmp (namespace, fi->full_name, nlen)
1616 && (p = strrchr (fi->full_name + nlen, separator))) {
1617 pname = g_strndup (fi->full_name, p - fi->full_name);
1618 pfi = g_hash_table_lookup (hash, pname);
1622 /* we are missing a folder in the heirarchy so
1623 * create a fake folder node */
1625 pfi = camel_folder_info_new ();
1628 pfi->display_name = strrchr (pname, separator);
1629 if (pfi->display_name != NULL)
1630 pfi->display_name = g_strdup (pfi->display_name + 1);
1632 pfi->display_name = g_strdup (pname);
1634 pfi->display_name = g_strdup (pname);
1636 pfi->full_name = g_strdup (pname);
1638 /* Since this is a "fake" folder
1639 * node, it is not selectable. */
1640 pfi->flags |= CAMEL_FOLDER_NOSELECT;
1642 g_hash_table_insert (hash, pname, pfi);
1643 g_ptr_array_add (folders, pfi);
1645 tail = (CamelFolderInfo *) &pfi->child;
1650 } else if (!top || !g_ascii_strcasecmp (fi->full_name, "Inbox"))
1653 g_hash_table_destroy (hash);
1655 /* Link together the top-level folders */
1657 for (i = 0; i < folders->len; i++) {
1658 fi = folders->pdata[i];
1661 fi->flags &= ~CAMEL_FOLDER_NOCHILDREN;
1663 if (fi->parent || fi == top)
1677 static CamelFolderInfo *
1678 folder_info_clone_rec (CamelFolderInfo *fi,
1679 CamelFolderInfo *parent)
1681 CamelFolderInfo *info;
1683 info = camel_folder_info_new ();
1684 info->parent = parent;
1685 info->full_name = g_strdup (fi->full_name);
1686 info->display_name = g_strdup (fi->display_name);
1687 info->unread = fi->unread;
1688 info->flags = fi->flags;
1691 info->next = folder_info_clone_rec (fi->next, parent);
1696 info->child = folder_info_clone_rec (fi->child, info);
1704 * camel_folder_info_clone:
1705 * @fi: a #CamelFolderInfo
1707 * Clones @fi recursively.
1709 * Returns: the cloned #CamelFolderInfo tree.
1712 camel_folder_info_clone (CamelFolderInfo *fi)
1717 return folder_info_clone_rec (fi, NULL);
1721 * camel_store_can_refresh_folder
1722 * @store: a #CamelStore
1723 * @info: a #CamelFolderInfo
1724 * @error: return location for a #GError, or %NULL
1726 * Returns if this folder (param info) should be checked for new mail or not.
1727 * It should not look into sub infos (info->child) or next infos, it should
1728 * return value only for the actual folder info.
1729 * Default behavior is that all Inbox folders are intended to be refreshed.
1731 * Returns: whether folder should be checked for new mails
1736 camel_store_can_refresh_folder (CamelStore *store,
1737 CamelFolderInfo *info,
1740 CamelStoreClass *class;
1742 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
1743 g_return_val_if_fail (info != NULL, FALSE);
1745 class = CAMEL_STORE_GET_CLASS (store);
1746 g_return_val_if_fail (class->can_refresh_folder != NULL, FALSE);
1748 return class->can_refresh_folder (store, info, error);
1753 * @store: a #CamelStore
1754 * @lock: lock type to lock
1756 * Locks @store's @lock. Unlock it with camel_store_unlock().
1761 camel_store_lock (CamelStore *store,
1762 CamelStoreLock lock)
1764 g_return_if_fail (CAMEL_IS_STORE (store));
1767 case CAMEL_STORE_FOLDER_LOCK:
1768 g_static_rec_mutex_lock (&store->priv->folder_lock);
1771 g_return_if_reached ();
1776 * camel_store_unlock:
1777 * @store: a #CamelStore
1778 * @lock: lock type to unlock
1780 * Unlocks @store's @lock, previously locked with camel_store_lock().
1785 camel_store_unlock (CamelStore *store,
1786 CamelStoreLock lock)
1788 g_return_if_fail (CAMEL_IS_STORE (store));
1791 case CAMEL_STORE_FOLDER_LOCK:
1792 g_static_rec_mutex_unlock (&store->priv->folder_lock);
1795 g_return_if_reached ();
1800 * camel_store_get_folder_sync:
1801 * @store: a #CamelStore
1802 * @folder_name: name of the folder to get
1803 * @flags: folder flags (create, save body index, etc)
1804 * @cancellable: optional #GCancellable object, or %NULL
1805 * @error: return location for a #GError, or %NULL
1807 * Gets a specific folder object from @store by name.
1809 * Returns: the requested #CamelFolder object, or %NULL on error
1814 camel_store_get_folder_sync (CamelStore *store,
1815 const gchar *folder_name,
1816 CamelStoreGetFolderFlags flags,
1817 GCancellable *cancellable,
1820 CamelStoreClass *class;
1821 CamelFolder *folder = NULL;
1823 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
1824 g_return_val_if_fail (folder_name != NULL, NULL);
1826 class = CAMEL_STORE_GET_CLASS (store);
1828 /* O_EXCL doesn't make sense if we aren't requesting
1829 * to also create the folder if it doesn't exist. */
1830 if (!(flags & CAMEL_STORE_FOLDER_CREATE))
1831 flags &= ~CAMEL_STORE_FOLDER_EXCL;
1833 /* Try cache first. */
1834 folder = camel_object_bag_reserve (store->folders, folder_name);
1835 if (folder != NULL && (flags & CAMEL_STORE_FOLDER_EXCL)) {
1837 error, CAMEL_ERROR, CAMEL_ERROR_GENERIC,
1838 _("Cannot create folder '%s': folder exists"),
1840 camel_object_bag_abort (store->folders, folder_name);
1841 g_object_unref (folder);
1845 if (folder == NULL) {
1846 CamelVeeFolder *vjunk = NULL;
1847 CamelVeeFolder *vtrash = NULL;
1848 gboolean folder_name_is_vjunk;
1849 gboolean folder_name_is_vtrash;
1850 gboolean store_uses_vjunk;
1851 gboolean store_uses_vtrash;
1854 ((store->flags & CAMEL_STORE_VJUNK) != 0);
1856 ((store->flags & CAMEL_STORE_VTRASH) != 0);
1857 folder_name_is_vjunk =
1859 (strcmp (folder_name, CAMEL_VJUNK_NAME) == 0);
1860 folder_name_is_vtrash =
1861 store_uses_vtrash &&
1862 (strcmp (folder_name, CAMEL_VTRASH_NAME) == 0);
1864 if (flags & CAMEL_STORE_IS_MIGRATING) {
1865 if (folder_name_is_vtrash) {
1866 if (store->folders != NULL)
1867 camel_object_bag_abort (
1868 store->folders, folder_name);
1872 if (folder_name_is_vjunk) {
1873 if (store->folders != NULL)
1874 camel_object_bag_abort (
1875 store->folders, folder_name);
1880 camel_operation_push_message (
1881 cancellable, _("Opening folder '%s'"), folder_name);
1883 if (folder_name_is_vtrash) {
1884 folder = class->get_trash_folder_sync (
1885 store, cancellable, error);
1886 CAMEL_CHECK_GERROR (
1887 store, get_trash_folder_sync,
1888 folder != NULL, error);
1889 } else if (folder_name_is_vjunk) {
1890 folder = class->get_junk_folder_sync (
1891 store, cancellable, error);
1892 CAMEL_CHECK_GERROR (
1893 store, get_junk_folder_sync,
1894 folder != NULL, error);
1896 folder = class->get_folder_sync (
1897 store, folder_name, flags,
1898 cancellable, error);
1899 CAMEL_CHECK_GERROR (
1900 store, get_folder_sync,
1901 folder != NULL, error);
1903 if (folder != NULL && store_uses_vjunk)
1904 vjunk = camel_object_bag_get (
1905 store->folders, CAMEL_VJUNK_NAME);
1907 if (folder != NULL && store_uses_vtrash)
1908 vtrash = camel_object_bag_get (
1909 store->folders, CAMEL_VTRASH_NAME);
1912 /* Release the folder name reservation before adding the
1913 * folder to the virtual Junk and Trash folders, just to
1914 * reduce the chance of deadlock. */
1916 camel_object_bag_add (
1917 store->folders, folder_name, folder);
1919 camel_object_bag_abort (
1920 store->folders, folder_name);
1922 /* If this is a normal folder and the store uses a
1923 * virtual Junk folder, let the virtual Junk folder
1924 * track this folder. */
1925 if (vjunk != NULL) {
1926 camel_vee_folder_add_folder (vjunk, folder, NULL);
1927 g_object_unref (vjunk);
1930 /* If this is a normal folder and the store uses a
1931 * virtual Trash folder, let the virtual Trash folder
1932 * track this folder. */
1933 if (vtrash != NULL) {
1934 camel_vee_folder_add_folder (vtrash, folder, NULL);
1935 g_object_unref (vtrash);
1938 camel_operation_pop_message (cancellable);
1941 camel_store_folder_opened (store, folder);
1948 * camel_store_get_folder:
1949 * @store: a #CamelStore
1950 * @folder_name: name of the folder to get
1951 * @flags: folder flags (create, save body index, etc)
1952 * @io_priority: the I/O priority of the request
1953 * @cancellable: optional #GCancellable object, or %NULL
1954 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
1955 * @user_data: data to pass to the callback function
1957 * Asynchronously gets a specific folder object from @store by name.
1959 * When the operation is finished, @callback will be called. You can then
1960 * call camel_store_get_folder_finish() to get the result of the operation.
1965 camel_store_get_folder (CamelStore *store,
1966 const gchar *folder_name,
1967 CamelStoreGetFolderFlags flags,
1969 GCancellable *cancellable,
1970 GAsyncReadyCallback callback,
1973 CamelStoreClass *class;
1975 g_return_if_fail (CAMEL_IS_STORE (store));
1976 g_return_if_fail (folder_name != NULL);
1978 class = CAMEL_STORE_GET_CLASS (store);
1979 g_return_if_fail (class->get_folder != NULL);
1982 store, folder_name, flags, io_priority,
1983 cancellable, callback, user_data);
1987 * camel_store_get_folder_finish:
1988 * @store: a #CamelStore
1989 * @result: a #GAsyncResult
1990 * @error: return location for a #GError, or %NULL
1992 * Finishes the operation started with camel_store_get_folder().
1994 * Returns: the requested #CamelFolder object, or %NULL on error
1999 camel_store_get_folder_finish (CamelStore *store,
2000 GAsyncResult *result,
2003 CamelStoreClass *class;
2005 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2006 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2008 class = CAMEL_STORE_GET_CLASS (store);
2009 g_return_val_if_fail (class->get_folder_finish != NULL, NULL);
2011 return class->get_folder_finish (store, result, error);
2015 * camel_store_get_folder_info_sync:
2016 * @store: a #CamelStore
2017 * @top: the name of the folder to start from
2018 * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
2019 * @cancellable: optional #GCancellable object, or %NULL
2020 * @error: return location for a #GError, or %NULL
2022 * This fetches information about the folder structure of @store,
2023 * starting with @top, and returns a tree of #CamelFolderInfo
2024 * structures. If @flags includes %CAMEL_STORE_FOLDER_INFO_SUBSCRIBED,
2025 * only subscribed folders will be listed. If the store doesn't support
2026 * subscriptions, then it will list all folders. If @flags includes
2027 * %CAMEL_STORE_FOLDER_INFO_RECURSIVE, the returned tree will include
2028 * all levels of hierarchy below @top. If not, it will only include
2029 * the immediate subfolders of @top. If @flags includes
2030 * %CAMEL_STORE_FOLDER_INFO_FAST, the unread_message_count fields of
2031 * some or all of the structures may be set to %-1, if the store cannot
2032 * determine that information quickly. If @flags includes
2033 * %CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL, don't include special virtual
2034 * folders (such as vTrash or vJunk).
2036 * The returned #CamelFolderInfo tree should be freed with
2037 * camel_store_free_folder_info().
2039 * The CAMEL_STORE_FOLDER_INFO_FAST flag should be considered
2040 * deprecated; most backends will behave the same whether it is
2041 * supplied or not. The only guaranteed way to get updated folder
2042 * counts is to both open the folder and invoke refresh_info() it.
2044 * Returns: a #CamelFolderInfo tree, or %NULL on error
2049 camel_store_get_folder_info_sync (CamelStore *store,
2051 CamelStoreGetFolderInfoFlags flags,
2052 GCancellable *cancellable,
2055 CamelStoreClass *class;
2056 CamelFolderInfo *info;
2059 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2061 class = CAMEL_STORE_GET_CLASS (store);
2062 g_return_val_if_fail (class->get_folder_info_sync != NULL, NULL);
2064 name = camel_service_get_name (CAMEL_SERVICE (store), TRUE);
2065 camel_operation_push_message (
2066 cancellable, _("Scanning folders in '%s'"), name);
2069 info = class->get_folder_info_sync (
2070 store, top, flags, cancellable, error);
2071 if (!(flags & CAMEL_STORE_FOLDER_INFO_SUBSCRIBED))
2072 CAMEL_CHECK_GERROR (
2073 store, get_folder_info_sync, info != NULL, error);
2075 if (info && (top == NULL || *top == '\0') && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) {
2076 if (store->flags & CAMEL_STORE_VTRASH)
2077 /* the name of the Trash folder, used for deleted messages */
2078 add_special_info (store, info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_TRASH);
2079 if (store->flags & CAMEL_STORE_VJUNK)
2080 /* the name of the Junk folder, used for spam messages */
2081 add_special_info (store, info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_JUNK);
2082 } else if (!info && top && (flags & CAMEL_STORE_FOLDER_INFO_NO_VIRTUAL) == 0) {
2083 CamelFolderInfo *root_info = NULL;
2085 if ((store->flags & CAMEL_STORE_VTRASH) != 0 && g_str_equal (top, CAMEL_VTRASH_NAME)) {
2086 root_info = class->get_folder_info_sync (store, NULL, flags & (~CAMEL_STORE_FOLDER_INFO_RECURSIVE), cancellable, error);
2088 add_special_info (store, root_info, CAMEL_VTRASH_NAME, _("Trash"), FALSE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_TRASH);
2089 } else if ((store->flags & CAMEL_STORE_VJUNK) != 0 && g_str_equal (top, CAMEL_VJUNK_NAME)) {
2090 root_info = class->get_folder_info_sync (store, NULL, flags & (~CAMEL_STORE_FOLDER_INFO_RECURSIVE), cancellable, error);
2092 add_special_info (store, root_info, CAMEL_VJUNK_NAME, _("Junk"), TRUE, CAMEL_FOLDER_VIRTUAL|CAMEL_FOLDER_SYSTEM|CAMEL_FOLDER_VTRASH|CAMEL_FOLDER_TYPE_JUNK);
2096 info = root_info->next;
2097 root_info->next = NULL;
2099 info->parent = NULL;
2101 camel_store_free_folder_info (store, root_info);
2105 camel_operation_pop_message (cancellable);
2107 if (camel_debug_start("store:folder_info")) {
2110 uid = camel_service_get_uid (CAMEL_SERVICE (store));
2112 "Get folder info(%p:%s, '%s') =\n",
2113 (gpointer) store, uid, top ? top : "<null>");
2122 * camel_store_get_folder_info:
2123 * @store: a #CamelStore
2124 * @top: the name of the folder to start from
2125 * @flags: various CAMEL_STORE_FOLDER_INFO_* flags to control behavior
2126 * @io_priority: the I/O priority of the request
2127 * @cancellable: optional #GCancellable object, or %NULL
2128 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2129 * @user_data: data to pass to the callback function
2131 * Asynchronously fetches information about the folder structure of @store,
2132 * starting with @top. For details of the behavior, see
2133 * camel_store_get_folder_info_sync().
2135 * When the operation is finished, @callback will be called. You can
2136 * then call camel_store_get_folder_info_finish() to get the result of
2142 camel_store_get_folder_info (CamelStore *store,
2144 CamelStoreGetFolderInfoFlags flags,
2146 GCancellable *cancellable,
2147 GAsyncReadyCallback callback,
2150 CamelStoreClass *class;
2152 g_return_if_fail (CAMEL_IS_STORE (store));
2154 class = CAMEL_STORE_GET_CLASS (store);
2155 g_return_if_fail (class->get_folder_info != NULL);
2157 class->get_folder_info (
2158 store, top, flags, io_priority,
2159 cancellable, callback, user_data);
2163 * camel_store_get_folder_info_finish:
2164 * @store: a #CamelStore
2165 * @result: a #GAsyncResult
2166 * @error: return location for a #GError, or %NULL
2168 * Finishes the operation started with camel_store_get_folder_info().
2169 * The returned #CamelFolderInfo tree should be freed with
2170 * camel_store_free_folder_info().
2172 * Returns: a #CamelFolderInfo tree, or %NULL on error
2177 camel_store_get_folder_info_finish (CamelStore *store,
2178 GAsyncResult *result,
2181 CamelStoreClass *class;
2183 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2184 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2186 class = CAMEL_STORE_GET_CLASS (store);
2187 g_return_val_if_fail (class->get_folder_info_finish != NULL, NULL);
2189 return class->get_folder_info_finish (store, result, error);
2193 * camel_store_get_inbox_folder_sync:
2194 * @store: a #CamelStore
2195 * @cancellable: optional #GCancellable object, or %NULL
2196 * @error: return location for a #GError, or %NULL
2198 * Gets the folder in @store into which new mail is delivered.
2200 * Returns: the inbox folder for @store, or %NULL on error or if no such
2206 camel_store_get_inbox_folder_sync (CamelStore *store,
2207 GCancellable *cancellable,
2210 CamelStoreClass *class;
2211 CamelFolder *folder;
2213 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2215 class = CAMEL_STORE_GET_CLASS (store);
2216 g_return_val_if_fail (class->get_inbox_folder_sync != NULL, NULL);
2218 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2220 /* Check for cancellation after locking. */
2221 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2222 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2226 folder = class->get_inbox_folder_sync (store, cancellable, error);
2227 CAMEL_CHECK_GERROR (
2228 store, get_inbox_folder_sync, folder != NULL, error);
2230 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2236 * camel_store_get_inbox_folder:
2237 * @store: a #CamelStore
2238 * @io_priority: the I/O priority of the request
2239 * @cancellable: optional #GCancellable object, or %NULL
2240 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2241 * @user_data: data to pass to the callback function
2243 * Asynchronously gets the folder in @store into which new mail is delivered.
2245 * When the operation is finished, @callback will be called. You can
2246 * then call camel_store_get_inbox_folder_finish() to get the result of
2252 camel_store_get_inbox_folder (CamelStore *store,
2254 GCancellable *cancellable,
2255 GAsyncReadyCallback callback,
2258 CamelStoreClass *class;
2260 g_return_if_fail (CAMEL_IS_STORE (store));
2262 class = CAMEL_STORE_GET_CLASS (store);
2263 g_return_if_fail (class->get_inbox_folder != NULL);
2265 class->get_inbox_folder (
2266 store, io_priority, cancellable, callback, user_data);
2270 * camel_store_get_inbox_folder_finish:
2271 * @store: a #CamelStore
2272 * @result: a #GAsyncResult
2273 * @error: return location for a #GError, or %NULL
2275 * Finishes the operation started with camel_store_get_inbox_folder().
2277 * Returns: the inbox folder for @store, or %NULL on error or if no such
2283 camel_store_get_inbox_folder_finish (CamelStore *store,
2284 GAsyncResult *result,
2287 CamelStoreClass *class;
2289 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2290 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2292 class = CAMEL_STORE_GET_CLASS (store);
2293 g_return_val_if_fail (class->get_inbox_folder_finish != NULL, NULL);
2295 return class->get_inbox_folder_finish (store, result, error);
2299 * camel_store_get_junk_folder_sync:
2300 * @store: a #CamelStore
2301 * @cancellable: optional #GCancellable object, or %NULL
2302 * @error: return location for a #GError, or %NULL
2304 * Gets the folder in @store into which junk is delivered.
2306 * Returns: the junk folder for @store, or %NULL on error or if no such
2312 camel_store_get_junk_folder_sync (CamelStore *store,
2313 GCancellable *cancellable,
2316 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2318 if ((store->flags & CAMEL_STORE_VJUNK) == 0) {
2319 CamelStoreClass *class;
2320 CamelFolder *folder;
2322 class = CAMEL_STORE_GET_CLASS (store);
2323 g_return_val_if_fail (class->get_junk_folder_sync != NULL, NULL);
2325 folder = class->get_junk_folder_sync (store, cancellable, error);
2326 CAMEL_CHECK_GERROR (
2327 store, get_junk_folder_sync, folder != NULL, error);
2332 return camel_store_get_folder_sync (
2333 store, CAMEL_VJUNK_NAME, 0, cancellable, error);
2337 * camel_store_get_junk_folder:
2338 * @store: a #CamelStore
2339 * @io_priority: the I/O priority of the request
2340 * @cancellable: optional #GCancellable object, or %NULL
2341 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2342 * @user_data: data to pass to the callback function
2344 * Asynchronously gets the folder in @store into which junk is delivered.
2346 * When the operation is finished, @callback will be called. You can
2347 * then call camel_store_get_junk_folder_finish() to get the result of
2353 camel_store_get_junk_folder (CamelStore *store,
2355 GCancellable *cancellable,
2356 GAsyncReadyCallback callback,
2359 CamelStoreClass *class;
2361 g_return_if_fail (CAMEL_IS_STORE (store));
2363 class = CAMEL_STORE_GET_CLASS (store);
2364 g_return_if_fail (class->get_junk_folder != NULL);
2366 class->get_junk_folder (
2367 store, io_priority, cancellable, callback, user_data);
2371 * camel_store_get_junk_folder_finish:
2372 * @store: a #CamelStore
2373 * @result: a #GAsyncResult
2374 * @error: return location for a #GError, or %NULL
2376 * Finishes the operation started with camel_store_get_junk_folder().
2378 * Returns: the junk folder for @store, or %NULL on error or if no such
2384 camel_store_get_junk_folder_finish (CamelStore *store,
2385 GAsyncResult *result,
2388 CamelStoreClass *class;
2390 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2391 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2393 class = CAMEL_STORE_GET_CLASS (store);
2394 g_return_val_if_fail (class->get_junk_folder_finish != NULL, NULL);
2396 return class->get_junk_folder_finish (store, result, error);
2400 * camel_store_get_trash_folder_sync:
2401 * @store: a #CamelStore
2402 * @cancellable: optional #GCancellable object, or %NULL
2403 * @error: return location for a #GError, or %NULL
2405 * Gets the folder in @store into which trash is delivered.
2407 * Returns: the trash folder for @store, or %NULL on error or if no such
2413 camel_store_get_trash_folder_sync (CamelStore *store,
2414 GCancellable *cancellable,
2417 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2419 if ((store->flags & CAMEL_STORE_VTRASH) == 0) {
2420 CamelStoreClass *class;
2421 CamelFolder *folder;
2423 class = CAMEL_STORE_GET_CLASS (store);
2424 g_return_val_if_fail (class->get_trash_folder_sync != NULL, NULL);
2426 folder = class->get_trash_folder_sync (
2427 store, cancellable, error);
2428 CAMEL_CHECK_GERROR (
2429 store, get_trash_folder_sync, folder != NULL, error);
2434 return camel_store_get_folder_sync (
2435 store, CAMEL_VTRASH_NAME, 0, cancellable, error);
2439 * camel_store_get_trash_folder:
2440 * @store: a #CamelStore
2441 * @io_priority: the I/O priority of the request
2442 * @cancellable: optional #GCancellable object, or %NULL
2443 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2444 * @user_data: data to pass to the callback function
2446 * Asynchronously gets the folder in @store into which trash is delivered.
2448 * When the operation is finished, @callback will be called. You can
2449 * then call camel_store_get_trash_folder_finish() to get the result of
2455 camel_store_get_trash_folder (CamelStore *store,
2457 GCancellable *cancellable,
2458 GAsyncReadyCallback callback,
2461 CamelStoreClass *class;
2463 g_return_if_fail (CAMEL_IS_STORE (store));
2465 class = CAMEL_STORE_GET_CLASS (store);
2466 g_return_if_fail (class->get_trash_folder != NULL);
2468 class->get_trash_folder (
2469 store, io_priority, cancellable, callback, user_data);
2473 * camel_store_get_trash_folder_finish:
2474 * @store: a #CamelStore
2475 * @result: a #GAsyncResult
2476 * @error: return location for a #GError, or %NULL
2478 * Finishes the operation started with camel_store_get_trash_folder().
2480 * Returns: the trash folder for @store, or %NULL on error or if no such
2486 camel_store_get_trash_folder_finish (CamelStore *store,
2487 GAsyncResult *result,
2490 CamelStoreClass *class;
2492 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2493 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2495 class = CAMEL_STORE_GET_CLASS (store);
2496 g_return_val_if_fail (class->get_trash_folder_finish != NULL, NULL);
2498 return class->get_trash_folder_finish (store, result, error);
2502 * camel_store_create_folder_sync:
2503 * @store: a #CamelStore
2504 * @parent_name: name of the new folder's parent, or %NULL
2505 * @folder_name: name of the folder to create
2506 * @cancellable: optional #GCancellable object, or %NULL
2507 * @error: return location for a #GError, or %NULL
2509 * Creates a new folder as a child of an existing folder.
2510 * @parent_name can be %NULL to create a new top-level folder.
2511 * The returned #CamelFolderInfo struct should be freed with
2512 * camel_store_free_folder_info().
2514 * Returns: info about the created folder, or %NULL on error
2519 camel_store_create_folder_sync (CamelStore *store,
2520 const gchar *parent_name,
2521 const gchar *folder_name,
2522 GCancellable *cancellable,
2525 CamelStoreClass *class;
2526 CamelFolderInfo *fi;
2528 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2529 g_return_val_if_fail (folder_name != NULL, NULL);
2531 class = CAMEL_STORE_GET_CLASS (store);
2532 g_return_val_if_fail (class->create_folder_sync != NULL, NULL);
2534 if ((parent_name == NULL || parent_name[0] == 0)
2535 && (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
2536 || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0))) {
2538 error, CAMEL_STORE_ERROR,
2539 CAMEL_STORE_ERROR_INVALID,
2540 _("Cannot create folder: %s: folder exists"),
2545 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2547 /* Check for cancellation after locking. */
2548 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2549 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2553 camel_operation_push_message (
2554 cancellable, _("Creating folder '%s'"), folder_name);
2556 fi = class->create_folder_sync (
2557 store, parent_name, folder_name, cancellable, error);
2558 CAMEL_CHECK_GERROR (store, create_folder_sync, fi != NULL, error);
2560 camel_operation_pop_message (cancellable);
2562 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2568 * camel_store_create_folder:
2569 * @store: a #CamelStore
2570 * @parent_name: name of the new folder's parent, or %NULL
2571 * @folder_name: name of the folder to create
2572 * @io_priority: the I/O priority of the request
2573 * @cancellable: optional #GCancellable object, or %NULL
2574 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2575 * @user_data: data to pass to the callback function
2577 * Asynchronously creates a new folder as a child of an existing folder.
2578 * @parent_name can be %NULL to create a new top-level folder.
2580 * When the operation is finished, @callback will be called. You can then
2581 * call camel_store_create_folder_finish() to get the result of the operation.
2586 camel_store_create_folder (CamelStore *store,
2587 const gchar *parent_name,
2588 const gchar *folder_name,
2590 GCancellable *cancellable,
2591 GAsyncReadyCallback callback,
2594 CamelStoreClass *class;
2596 g_return_if_fail (CAMEL_IS_STORE (store));
2597 g_return_if_fail (folder_name != NULL);
2599 class = CAMEL_STORE_GET_CLASS (store);
2600 g_return_if_fail (class->create_folder != NULL);
2602 class->create_folder (
2603 store, parent_name, folder_name, io_priority,
2604 cancellable, callback, user_data);
2608 * camel_store_create_folder_finish:
2609 * @store: a #CamelStore
2610 * @result: a #GAsyncResult
2611 * @error: return location for a #GError, or %NULL
2613 * Finishes the operation started with camel_store_create_folder().
2614 * The returned #CamelFolderInfo struct should be freed with
2615 * camel_store_free_folder_info().
2617 * Returns: info about the created folder, or %NULL on error
2622 camel_store_create_folder_finish (CamelStore *store,
2623 GAsyncResult *result,
2626 CamelStoreClass *class;
2628 g_return_val_if_fail (CAMEL_IS_STORE (store), NULL);
2629 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), NULL);
2631 class = CAMEL_STORE_GET_CLASS (store);
2632 g_return_val_if_fail (class->create_folder_finish != NULL, NULL);
2634 return class->create_folder_finish (store, result, error);
2638 * camel_store_delete_folder_sync:
2639 * @store: a #CamelStore
2640 * @folder_name: name of the folder to delete
2641 * @cancellable: optional #GCancellable object, or %NULL
2642 * @error: return location for a #GError, or %NULL
2644 * Deletes the folder described by @folder_name. The folder must be empty.
2646 * Returns: %TRUE on success, %FALSE on failure
2651 camel_store_delete_folder_sync (CamelStore *store,
2652 const gchar *folder_name,
2653 GCancellable *cancellable,
2656 CamelStoreClass *class;
2658 GError *local_error = NULL, **check_error = NULL;
2660 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2661 g_return_val_if_fail (folder_name != NULL, FALSE);
2663 class = CAMEL_STORE_GET_CLASS (store);
2664 g_return_val_if_fail (class->delete_folder_sync != NULL, FALSE);
2666 /* TODO: should probably be a parameter/bit on the storeinfo */
2667 if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (folder_name, CAMEL_VTRASH_NAME) == 0)
2668 || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (folder_name, CAMEL_VJUNK_NAME) == 0)) {
2670 error, CAMEL_STORE_ERROR,
2671 CAMEL_STORE_ERROR_NO_FOLDER,
2672 _("Cannot delete folder: %s: Invalid operation"),
2677 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2679 /* Check for cancellation after locking. */
2680 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2681 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2685 success = class->delete_folder_sync (
2686 store, folder_name, cancellable, &local_error);
2688 check_error = &local_error;
2689 CAMEL_CHECK_GERROR (store, delete_folder_sync, success, check_error);
2691 /* ignore 'no such table' errors */
2692 if (local_error != NULL &&
2693 g_ascii_strncasecmp (local_error->message, "no such table", 13) == 0)
2694 g_clear_error (&local_error);
2696 if (local_error == NULL)
2697 cs_delete_cached_folder (store, folder_name);
2699 g_propagate_error (error, local_error);
2701 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2707 * camel_store_delete_folder:
2708 * @store: a #CamelStore
2709 * @folder_name: name of the folder to delete
2710 * @io_priority: the I/O priority of the request
2711 * @cancellable: optional #GCancellable object, or %NULL
2712 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2713 * @user_data: data to pass to the callback function
2715 * Asynchronously deletes the folder described by @folder_name. The
2716 * folder must be empty.
2718 * When the operation is finished, @callback will be called. You can then
2719 * call camel_store_delete_folder_finish() to get the result of the operation.
2724 camel_store_delete_folder (CamelStore *store,
2725 const gchar *folder_name,
2727 GCancellable *cancellable,
2728 GAsyncReadyCallback callback,
2731 CamelStoreClass *class;
2733 g_return_if_fail (CAMEL_IS_STORE (store));
2734 g_return_if_fail (folder_name != NULL);
2736 class = CAMEL_STORE_GET_CLASS (store);
2737 g_return_if_fail (class->delete_folder != NULL);
2739 class->delete_folder (
2740 store, folder_name, io_priority,
2741 cancellable, callback, user_data);
2745 * camel_store_delete_folder_finish:
2746 * @store: a #CamelStore
2747 * @result: a #GAsyncResult
2748 * @error: return location for a #GError, or %NULL
2750 * Finishes the operation started with camel_store_delete_folder().
2752 * Returns: %TRUE on success, %FALSE on error
2757 camel_store_delete_folder_finish (CamelStore *store,
2758 GAsyncResult *result,
2761 CamelStoreClass *class;
2763 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2764 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2766 class = CAMEL_STORE_GET_CLASS (store);
2767 g_return_val_if_fail (class->delete_folder_finish != NULL, FALSE);
2769 return class->delete_folder_finish (store, result, error);
2773 * camel_store_rename_folder_sync:
2774 * @store: a #CamelStore
2775 * @old_name: the current name of the folder
2776 * @new_name: the new name of the folder
2777 * @cancellable: optional #GCancellable object, or %NULL
2778 * @error: return location for a #GError, or %NULL
2780 * Renames the folder described by @old_name to @new_name.
2782 * Returns: %TRUE on success, %FALSE on error
2787 camel_store_rename_folder_sync (CamelStore *store,
2788 const gchar *old_namein,
2789 const gchar *new_name,
2790 GCancellable *cancellable,
2793 CamelStoreClass *class;
2794 CamelFolder *folder;
2795 gint i, oldlen, namelen;
2796 GPtrArray *folders = NULL;
2800 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2801 g_return_val_if_fail (old_namein != NULL, FALSE);
2802 g_return_val_if_fail (new_name != NULL, FALSE);
2804 class = CAMEL_STORE_GET_CLASS (store);
2805 g_return_val_if_fail (class->rename_folder_sync != NULL, FALSE);
2807 if (strcmp (old_namein, new_name) == 0)
2810 if (((store->flags & CAMEL_STORE_VTRASH) && strcmp (old_namein, CAMEL_VTRASH_NAME) == 0)
2811 || ((store->flags & CAMEL_STORE_VJUNK) && strcmp (old_namein, CAMEL_VJUNK_NAME) == 0)) {
2813 error, CAMEL_STORE_ERROR,
2814 CAMEL_STORE_ERROR_NO_FOLDER,
2815 _("Cannot rename folder: %s: Invalid operation"),
2820 /* need to save this, since old_namein might be folder->full_name, which could go away */
2821 old_name = g_strdup (old_namein);
2822 oldlen = strlen (old_name);
2824 camel_store_lock (store, CAMEL_STORE_FOLDER_LOCK);
2826 /* Check for cancellation after locking. */
2827 if (g_cancellable_set_error_if_cancelled (cancellable, error)) {
2828 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2832 /* If the folder is open (or any subfolders of the open folder)
2833 * We need to rename them atomically with renaming the actual
2835 folders = camel_object_bag_list (store->folders);
2836 for (i = 0; folders && i < folders->len; i++) {
2837 const gchar *full_name;
2839 folder = folders->pdata[i];
2840 full_name = camel_folder_get_full_name (folder);
2842 namelen = strlen (full_name);
2843 if ((namelen == oldlen &&
2844 strcmp (full_name, old_name) == 0)
2845 || ((namelen > oldlen)
2846 && strncmp (full_name, old_name, oldlen) == 0
2847 && full_name[oldlen] == '/')) {
2848 camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
2850 g_ptr_array_remove_index_fast (folders, i);
2852 g_object_unref (folder);
2856 /* Now try the real rename (will emit renamed signal) */
2857 success = class->rename_folder_sync (
2858 store, old_name, new_name, cancellable, error);
2859 CAMEL_CHECK_GERROR (store, rename_folder_sync, success, error);
2861 /* If it worked, update all open folders/unlock them */
2864 CamelStoreGetFolderInfoFlags flags;
2865 CamelFolderInfo *folder_info;
2867 flags = CAMEL_STORE_FOLDER_INFO_RECURSIVE;
2869 for (i = 0; i < folders->len; i++) {
2870 const gchar *full_name;
2873 folder = folders->pdata[i];
2874 full_name = camel_folder_get_full_name (folder);
2876 new = g_strdup_printf("%s%s", new_name, full_name + strlen(old_name));
2877 camel_object_bag_rekey (store->folders, folder, new);
2878 camel_folder_rename (folder, new);
2881 camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
2882 g_object_unref (folder);
2885 /* Emit renamed signal */
2886 if (CAMEL_IS_SUBSCRIBABLE (store))
2887 flags |= CAMEL_STORE_FOLDER_INFO_SUBSCRIBED;
2889 folder_info = class->get_folder_info_sync (
2890 store, new_name, flags, cancellable, error);
2891 CAMEL_CHECK_GERROR (store, get_folder_info, folder_info != NULL, error);
2893 if (folder_info != NULL) {
2894 camel_store_folder_renamed (store, old_name, folder_info);
2895 class->free_folder_info (store, folder_info);
2898 /* Failed, just unlock our folders for re-use */
2899 for (i = 0; i < folders->len; i++) {
2900 folder = folders->pdata[i];
2901 camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
2902 g_object_unref (folder);
2907 camel_store_unlock (store, CAMEL_STORE_FOLDER_LOCK);
2909 g_ptr_array_free (folders, TRUE);
2916 * camel_store_rename_folder:
2917 * @store: a #CamelStore
2918 * @old_name: the current name of the folder
2919 * @new_name: the new name of the folder
2920 * @io_priority: the I/O priority of the request
2921 * @cancellable: optional #GCancellable object, or %NULL
2922 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
2923 * @user_data: data to pass to the callback function
2925 * Asynchronously renames the folder described by @old_name to @new_name.
2927 * When the operation is finished, @callback will be called. You can then
2928 * call camel_store_rename_folder_finish() to get the result of the operation.
2933 camel_store_rename_folder (CamelStore *store,
2934 const gchar *old_name,
2935 const gchar *new_name,
2937 GCancellable *cancellable,
2938 GAsyncReadyCallback callback,
2941 CamelStoreClass *class;
2943 g_return_if_fail (CAMEL_IS_STORE (store));
2944 g_return_if_fail (old_name != NULL);
2945 g_return_if_fail (new_name != NULL);
2947 class = CAMEL_STORE_GET_CLASS (store);
2948 g_return_if_fail (class->rename_folder != NULL);
2950 class->rename_folder (
2951 store, old_name, new_name, io_priority,
2952 cancellable, callback, user_data);
2956 * camel_store_rename_folder_finish:
2957 * @store: a #CamelStore
2958 * @result: a #GAsyncResult
2959 * @error: return location for a #GError, or %NULL
2961 * Finishes the operation started with camel_store_rename_folder().
2963 * Returns: %TRUE on success, %FALSE on error
2968 camel_store_rename_folder_finish (CamelStore *store,
2969 GAsyncResult *result,
2972 CamelStoreClass *class;
2974 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
2975 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
2977 class = CAMEL_STORE_GET_CLASS (store);
2978 g_return_val_if_fail (class->rename_folder_finish != NULL, FALSE);
2980 return class->rename_folder_finish (store, result, error);
2984 * camel_store_synchronize_sync:
2985 * @store: a #CamelStore
2986 * @expunge: whether to expunge after synchronizing
2987 * @cancellable: optional #GCancellable object, or %NULL
2988 * @error: return location for a #GError, or %NULL
2990 * Synchronizes any changes that have been made to @store and its folders
2991 * with the real store.
2993 * Returns: %TRUE on success, %FALSE on error
2998 camel_store_synchronize_sync (CamelStore *store,
3000 GCancellable *cancellable,
3003 CamelStoreClass *class;
3006 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
3008 class = CAMEL_STORE_GET_CLASS (store);
3009 g_return_val_if_fail (class->synchronize_sync != NULL, FALSE);
3011 success = class->synchronize_sync (store, expunge, cancellable, error);
3012 CAMEL_CHECK_GERROR (store, synchronize_sync, success, error);
3018 * camel_store_synchronize:
3019 * @store: a #CamelStore
3020 * @expunge: whether to expunge after synchronizing
3021 * @io_priority: the I/O priority of the request
3022 * @cancellable: optional #GCancellable object, or %NULL
3023 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3024 * @user_data: data to pass to the callback function
3026 * Synchronizes any changes that have been made to @store and its folders
3027 * with the real store asynchronously.
3029 * When the operation is finished, @callback will be called. You can then
3030 * call camel_store_synchronize_finish() to get the result of the operation.
3035 camel_store_synchronize (CamelStore *store,
3038 GCancellable *cancellable,
3039 GAsyncReadyCallback callback,
3042 CamelStoreClass *class;
3044 g_return_if_fail (CAMEL_IS_STORE (store));
3046 class = CAMEL_STORE_GET_CLASS (store);
3047 g_return_if_fail (class->synchronize != NULL);
3049 class->synchronize (
3050 store, expunge, io_priority,
3051 cancellable, callback, user_data);
3055 * camel_store_synchronize_finish:
3056 * @store: a #CamelStore
3057 * @result: a #GAsyncResult
3058 * @error: return location for a #GError, or %NULL
3060 * Finishes the operation started with camel_store_synchronize().
3062 * Returns: %TRUE on success, %FALSE on error
3067 camel_store_synchronize_finish (CamelStore *store,
3068 GAsyncResult *result,
3071 CamelStoreClass *class;
3073 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
3074 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3076 class = CAMEL_STORE_GET_CLASS (store);
3077 g_return_val_if_fail (class->synchronize_finish != NULL, FALSE);
3079 return class->synchronize_finish (store, result, error);
3083 * camel_store_noop_sync:
3084 * @store: a #CamelStore
3085 * @cancellable: optional #GCancellable object, or %NULL
3086 * @error: return location for a #GError, or %NULL
3088 * Pings @store so its connection doesn't time out.
3090 * Returns: %TRUE on success, %FALSE on error
3095 camel_store_noop_sync (CamelStore *store,
3096 GCancellable *cancellable,
3099 CamelStoreClass *class;
3102 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
3104 class = CAMEL_STORE_GET_CLASS (store);
3105 g_return_val_if_fail (class->noop_sync != NULL, FALSE);
3107 success = class->noop_sync (store, cancellable, error);
3108 CAMEL_CHECK_GERROR (store, noop_sync, success, error);
3115 * @store: a #CamelStore
3116 * @io_priority: the I/O priority of the request
3117 * @cancellable: optional #GCancellable object, or %NULL
3118 * @callback: a #GAsyncReadyCallback to call when the request is satisfied
3119 * @user_data: data to pass to the callback function
3121 * Pings @store asynchronously so its connection doesn't time out.
3123 * When the operation is finished, @callback will be called. You can then
3124 * call camel_store_noop_finish() to get the result of the operation.
3129 camel_store_noop (CamelStore *store,
3131 GCancellable *cancellable,
3132 GAsyncReadyCallback callback,
3135 CamelStoreClass *class;
3137 g_return_if_fail (CAMEL_IS_STORE (store));
3139 class = CAMEL_STORE_GET_CLASS (store);
3140 g_return_if_fail (class->noop != NULL);
3142 class->noop (store, io_priority, cancellable, callback, user_data);
3146 * camel_store_noop_finish:
3147 * @store: a #CamelStore
3148 * @result: a #GAsyncResult
3149 * @error: return location for a #GError, or %NULL
3151 * Finishes the operation started with camel_store_noop().
3153 * Returns: %TRUE on success, %FALSE on error
3158 camel_store_noop_finish (CamelStore *store,
3159 GAsyncResult *result,
3162 CamelStoreClass *class;
3164 g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
3165 g_return_val_if_fail (G_IS_ASYNC_RESULT (result), FALSE);
3167 class = CAMEL_STORE_GET_CLASS (store);
3168 g_return_val_if_fail (class->noop_finish != NULL, FALSE);
3170 return class->noop_finish (store, result, error);