[evolution-data-server] I#273 - Camel: Save folder changes periodically



commit b7397de8adef852744bc8d18c7aa55a933778fe2
Author: Milan Crha <mcrha redhat com>
Date:   Thu Nov 19 16:49:51 2020 +0100

    I#273 - Camel: Save folder changes periodically
    
    Closes https://gitlab.gnome.org/GNOME/evolution-data-server/-/issues/273

 src/camel/camel-folder.c           | 133 ++++++++++++++++++++++++++++++
 src/camel/camel-local-settings.h   |  12 +--
 src/camel/camel-offline-folder.c   | 161 -------------------------------------
 src/camel/camel-offline-settings.c |  45 ++---------
 src/camel/camel-offline-settings.h |   2 +
 src/camel/camel-offline-store.c    |  22 +++++
 src/camel/camel-store-settings.c   |  77 +++++++++++++++++-
 src/camel/camel-store-settings.h   |   5 ++
 src/camel/camel-store.c            |  31 +++++++
 src/camel/camel-store.h            |   6 +-
 src/camel/camel-vee-store.c        |   8 ++
 11 files changed, 295 insertions(+), 207 deletions(-)
---
diff --git a/src/camel/camel-folder.c b/src/camel/camel-folder.c
index 9298e5674..e418b0a5b 100644
--- a/src/camel/camel-folder.c
+++ b/src/camel/camel-folder.c
@@ -36,6 +36,7 @@
 #include "camel-operation.h"
 #include "camel-session.h"
 #include "camel-store.h"
+#include "camel-store-settings.h"
 #include "camel-vtrash-folder.h"
 #include "camel-string-utils.h"
 
@@ -70,6 +71,10 @@ struct _CamelFolderPrivate {
 
        CamelThreeState mark_seen;
        gint mark_seen_timeout;
+
+       GMutex store_changes_lock;
+       guint store_changes_id;
+       gboolean store_changes_after_frozen;
 };
 
 struct _AsyncContext {
@@ -133,6 +138,110 @@ G_DEFINE_BOXED_TYPE (CamelFolderQuotaInfo,
                camel_folder_quota_info_clone,
                camel_folder_quota_info_free)
 
+
+static void
+folder_store_changes_job_cb (CamelSession *session,
+                            GCancellable *cancellable,
+                            gpointer user_data,
+                            GError **error)
+{
+       CamelFolder *folder = user_data;
+
+       g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+       camel_folder_synchronize_sync (folder, FALSE, cancellable, error);
+}
+
+static gboolean
+folder_schedule_store_changes_job (gpointer user_data)
+{
+       CamelFolder *folder = user_data;
+       GSource *source;
+
+       source = g_main_current_source ();
+
+       if (g_source_is_destroyed (source))
+               return FALSE;
+
+       g_return_val_if_fail (CAMEL_IS_FOLDER (folder), FALSE);
+
+       g_mutex_lock (&folder->priv->store_changes_lock);
+
+       if (folder->priv->store_changes_id == g_source_get_id (source)) {
+               CamelSession *session;
+               CamelStore *parent_store;
+
+               folder->priv->store_changes_id = 0;
+
+               parent_store = camel_folder_get_parent_store (folder);
+               session = parent_store ? camel_service_ref_session (CAMEL_SERVICE (parent_store)) : NULL;
+               if (session) {
+                       gchar *description;
+
+                       /* Translators: The first “%s” is replaced with an account name and the second “%s”
+                          is replaced with a full path name. The spaces around “:” are intentional, as
+                          the whole “%s : %s” is meant as an absolute identification of the folder. */
+                       description = g_strdup_printf (_("Storing changes in folder “%s : %s”"),
+                               camel_service_get_display_name (CAMEL_SERVICE (parent_store)),
+                               camel_folder_get_full_name (folder));
+
+                       camel_session_submit_job (session, description,
+                               folder_store_changes_job_cb,
+                               g_object_ref (folder), g_object_unref);
+
+                       g_free (description);
+               }
+
+               g_clear_object (&session);
+       }
+
+       g_mutex_unlock (&folder->priv->store_changes_lock);
+
+       return FALSE;
+}
+
+static void
+folder_maybe_schedule_folder_change_store (CamelFolder *folder)
+{
+       CamelStore *store;
+
+       g_return_if_fail (CAMEL_IS_FOLDER (folder));
+
+       g_mutex_lock (&folder->priv->store_changes_lock);
+
+       if (folder->priv->store_changes_id)
+               g_source_remove (folder->priv->store_changes_id);
+       folder->priv->store_changes_id = 0;
+       folder->priv->store_changes_after_frozen = FALSE;
+
+       if (camel_folder_is_frozen (folder)) {
+               folder->priv->store_changes_after_frozen = TRUE;
+               g_mutex_unlock (&folder->priv->store_changes_lock);
+
+               return;
+       }
+
+       store = camel_folder_get_parent_store (folder);
+
+       if (store && camel_store_get_can_auto_save_changes (store)) {
+               CamelSettings *settings;
+               gint interval = -1;
+
+               settings = camel_service_ref_settings (CAMEL_SERVICE (store));
+               if (settings && CAMEL_IS_STORE_SETTINGS (settings))
+                       interval = camel_store_settings_get_store_changes_interval (CAMEL_STORE_SETTINGS 
(settings));
+               g_clear_object (&settings);
+
+               if (interval == 0)
+                       folder_schedule_store_changes_job (folder);
+               else if (interval > 0)
+                       folder->priv->store_changes_id = g_timeout_add_seconds (interval,
+                               folder_schedule_store_changes_job, folder);
+       }
+
+       g_mutex_unlock (&folder->priv->store_changes_lock);
+}
+
 static void
 async_context_free (AsyncContext *async_context)
 {
@@ -189,6 +298,9 @@ folder_emit_changed_cb (gpointer user_data)
 
        g_signal_emit (folder, signals[CHANGED], 0, changes);
 
+       if (changes && changes->uid_changed && changes->uid_changed->len > 0)
+               folder_maybe_schedule_folder_change_store (folder);
+
        camel_folder_change_info_free (changes);
 
        return FALSE;
@@ -687,6 +799,12 @@ folder_dispose (GObject *object)
                folder->priv->parent_store = NULL;
        }
 
+       g_mutex_lock (&folder->priv->store_changes_lock);
+       if (folder->priv->store_changes_id)
+               g_source_remove (folder->priv->store_changes_id);
+       folder->priv->store_changes_id = 0;
+       g_mutex_unlock (&folder->priv->store_changes_lock);
+
        /* Chain up to parent's dispose () method. */
        G_OBJECT_CLASS (camel_folder_parent_class)->dispose (object);
 }
@@ -711,6 +829,7 @@ folder_finalize (GObject *object)
 
        g_rec_mutex_clear (&priv->lock);
        g_mutex_clear (&priv->change_lock);
+       g_mutex_clear (&priv->store_changes_lock);
 
        /* Chain up to parent's finalize () method. */
        G_OBJECT_CLASS (camel_folder_parent_class)->finalize (object);
@@ -1018,6 +1137,18 @@ folder_thaw (CamelFolder *folder)
                if (folder->priv->summary)
                        camel_folder_summary_save (folder->priv->summary, NULL);
        }
+
+       if (!camel_folder_is_frozen (folder)) {
+               g_mutex_lock (&folder->priv->store_changes_lock);
+               if (folder->priv->store_changes_after_frozen) {
+                       folder->priv->store_changes_after_frozen = FALSE;
+                       g_mutex_unlock (&folder->priv->store_changes_lock);
+
+                       folder_maybe_schedule_folder_change_store (folder);
+               } else {
+                       g_mutex_unlock (&folder->priv->store_changes_lock);
+               }
+       }
 }
 
 static gboolean
@@ -1422,10 +1553,12 @@ camel_folder_init (CamelFolder *folder)
        folder->priv = camel_folder_get_instance_private (folder);
        folder->priv->frozen = 0;
        folder->priv->changed_frozen = camel_folder_change_info_new ();
+       folder->priv->store_changes_after_frozen = FALSE;
 
        g_rec_mutex_init (&folder->priv->lock);
        g_mutex_init (&folder->priv->change_lock);
        g_mutex_init (&folder->priv->property_lock);
+       g_mutex_init (&folder->priv->store_changes_lock);
 }
 
 G_DEFINE_QUARK (camel-folder-error-quark, camel_folder_error)
diff --git a/src/camel/camel-local-settings.h b/src/camel/camel-local-settings.h
index ea5b76cce..04c705e41 100644
--- a/src/camel/camel-local-settings.h
+++ b/src/camel/camel-local-settings.h
@@ -77,15 +77,15 @@ gchar *             camel_local_settings_dup_path   (CamelLocalSettings *settings);
 void           camel_local_settings_set_path   (CamelLocalSettings *settings,
                                                 const gchar *path);
 gboolean       camel_local_settings_get_filter_all
-                                       (CamelLocalSettings *settings);
+                                               (CamelLocalSettings *settings);
 void           camel_local_settings_set_filter_all
-                                       (CamelLocalSettings *settings,
-                                        gboolean filter_all);
+                                               (CamelLocalSettings *settings,
+                                                gboolean filter_all);
 gboolean       camel_local_settings_get_filter_junk
-                                       (CamelLocalSettings *settings);
+                                               (CamelLocalSettings *settings);
 void           camel_local_settings_set_filter_junk
-                                       (CamelLocalSettings *settings,
-                                        gboolean filter_junk);
+                                               (CamelLocalSettings *settings,
+                                                gboolean filter_junk);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-offline-folder.c b/src/camel/camel-offline-folder.c
index abaf7bd6a..270fd18b3 100644
--- a/src/camel/camel-offline-folder.c
+++ b/src/camel/camel-offline-folder.c
@@ -37,10 +37,6 @@ typedef struct _OfflineDownsyncData OfflineDownsyncData;
 struct _CamelOfflineFolderPrivate {
        CamelThreeState offline_sync;
 
-       GMutex store_changes_lock;
-       guint store_changes_id;
-       gboolean store_changes_after_frozen;
-
        GMutex ongoing_downloads_lock;
        GHashTable *ongoing_downloads; /* gchar * UID ~> g_thread_self() */
 };
@@ -233,112 +229,6 @@ offline_folder_downsync_background (CamelSession *session,
        camel_operation_pop_message (cancellable);
 }
 
-static void
-offline_folder_store_changes_job_cb (CamelSession *session,
-                                    GCancellable *cancellable,
-                                    gpointer user_data,
-                                    GError **error)
-{
-       CamelFolder *folder = user_data;
-
-       g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder));
-
-       camel_folder_synchronize_sync (folder, FALSE, cancellable, error);
-}
-
-static gboolean
-offline_folder_schedule_store_changes_job (gpointer user_data)
-{
-       CamelOfflineFolder *offline_folder = user_data;
-       GSource *source;
-
-       source = g_main_current_source ();
-
-       if (g_source_is_destroyed (source))
-               return FALSE;
-
-       g_return_val_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline_folder), FALSE);
-
-       g_mutex_lock (&offline_folder->priv->store_changes_lock);
-       if (offline_folder->priv->store_changes_id == g_source_get_id (source)) {
-               CamelSession *session;
-               CamelStore *parent_store;
-
-               offline_folder->priv->store_changes_id = 0;
-
-               parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (offline_folder));
-               session = parent_store ? camel_service_ref_session (CAMEL_SERVICE (parent_store)) : NULL;
-               if (session) {
-                       gchar *description;
-
-                       /* Translators: The first “%s” is replaced with an account name and the second “%s”
-                          is replaced with a full path name. The spaces around “:” are intentional, as
-                          the whole “%s : %s” is meant as an absolute identification of the folder. */
-                       description = g_strdup_printf (_("Storing changes in folder “%s : %s”"),
-                               camel_service_get_display_name (CAMEL_SERVICE (parent_store)),
-                               camel_folder_get_full_name (CAMEL_FOLDER (offline_folder)));
-
-                       camel_session_submit_job (session, description,
-                               offline_folder_store_changes_job_cb,
-                               g_object_ref (offline_folder), g_object_unref);
-
-                       g_free (description);
-               }
-
-               g_clear_object (&session);
-       }
-       g_mutex_unlock (&offline_folder->priv->store_changes_lock);
-
-       return FALSE;
-}
-
-static void
-offline_folder_maybe_schedule_folder_change_store (CamelOfflineFolder *offline_folder)
-{
-       CamelSession *session;
-       CamelStore *store;
-
-       g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (offline_folder));
-
-       g_mutex_lock (&offline_folder->priv->store_changes_lock);
-
-       if (offline_folder->priv->store_changes_id)
-               g_source_remove (offline_folder->priv->store_changes_id);
-       offline_folder->priv->store_changes_id = 0;
-       offline_folder->priv->store_changes_after_frozen = FALSE;
-
-       if (camel_folder_is_frozen (CAMEL_FOLDER (offline_folder))) {
-               offline_folder->priv->store_changes_after_frozen = TRUE;
-               g_mutex_unlock (&offline_folder->priv->store_changes_lock);
-
-               return;
-       }
-
-       store = camel_folder_get_parent_store (CAMEL_FOLDER (offline_folder));
-       session = store ? camel_service_ref_session (CAMEL_SERVICE (store)) : NULL;
-
-       if (session && camel_session_get_online (session) && CAMEL_IS_OFFLINE_STORE (store) &&
-           camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store))) {
-               CamelSettings *settings;
-               gint interval = -1;
-
-               settings = camel_service_ref_settings (CAMEL_SERVICE (store));
-               if (settings && CAMEL_IS_OFFLINE_SETTINGS (settings))
-                       interval = camel_offline_settings_get_store_changes_interval (CAMEL_OFFLINE_SETTINGS 
(settings));
-               g_clear_object (&settings);
-
-               if (interval == 0)
-                       offline_folder_schedule_store_changes_job (offline_folder);
-               else if (interval > 0)
-                       offline_folder->priv->store_changes_id = g_timeout_add_seconds (interval,
-                               offline_folder_schedule_store_changes_job, offline_folder);
-       }
-
-       g_clear_object (&session);
-
-       g_mutex_unlock (&offline_folder->priv->store_changes_lock);
-}
-
 static void
 offline_folder_changed (CamelFolder *folder,
                         CamelFolderChangeInfo *changes)
@@ -380,9 +270,6 @@ offline_folder_changed (CamelFolder *folder,
        }
 
        g_object_unref (session);
-
-       if (changes && changes->uid_changed && changes->uid_changed->len > 0)
-               offline_folder_maybe_schedule_folder_change_store (CAMEL_OFFLINE_FOLDER (folder));
 }
 
 static void
@@ -419,27 +306,11 @@ offline_folder_get_property (GObject *object,
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
 }
 
-static void
-offline_folder_dispose (GObject *object)
-{
-       CamelOfflineFolder *offline_folder = CAMEL_OFFLINE_FOLDER (object);
-
-       g_mutex_lock (&offline_folder->priv->store_changes_lock);
-       if (offline_folder->priv->store_changes_id)
-               g_source_remove (offline_folder->priv->store_changes_id);
-       offline_folder->priv->store_changes_id = 0;
-       g_mutex_unlock (&offline_folder->priv->store_changes_lock);
-
-       /* Chain up to parent's method. */
-       G_OBJECT_CLASS (camel_offline_folder_parent_class)->dispose (object);
-}
-
 static void
 offline_folder_finalize (GObject *object)
 {
        CamelOfflineFolder *offline_folder = CAMEL_OFFLINE_FOLDER (object);
 
-       g_mutex_clear (&offline_folder->priv->store_changes_lock);
        g_mutex_clear (&offline_folder->priv->ongoing_downloads_lock);
 
        g_hash_table_destroy (offline_folder->priv->ongoing_downloads);
@@ -448,31 +319,6 @@ offline_folder_finalize (GObject *object)
        G_OBJECT_CLASS (camel_offline_folder_parent_class)->finalize (object);
 }
 
-static void
-offline_folder_thaw (CamelFolder *folder)
-{
-       /* Chain up to parent's method. */
-       CAMEL_FOLDER_CLASS (camel_offline_folder_parent_class)->thaw (folder);
-
-       if (!camel_folder_is_frozen (folder)) {
-               CamelOfflineFolder *offline_folder;
-
-               g_return_if_fail (CAMEL_IS_OFFLINE_FOLDER (folder));
-
-               offline_folder = CAMEL_OFFLINE_FOLDER (folder);
-
-               g_mutex_lock (&offline_folder->priv->store_changes_lock);
-               if (offline_folder->priv->store_changes_after_frozen) {
-                       offline_folder->priv->store_changes_after_frozen = FALSE;
-                       g_mutex_unlock (&offline_folder->priv->store_changes_lock);
-
-                       offline_folder_maybe_schedule_folder_change_store (offline_folder);
-               } else {
-                       g_mutex_unlock (&offline_folder->priv->store_changes_lock);
-               }
-       }
-}
-
 static gboolean
 offline_folder_downsync_sync (CamelOfflineFolder *offline,
                               const gchar *expression,
@@ -621,17 +467,12 @@ static void
 camel_offline_folder_class_init (CamelOfflineFolderClass *class)
 {
        GObjectClass *object_class;
-       CamelFolderClass *folder_class;
 
        object_class = G_OBJECT_CLASS (class);
        object_class->set_property = offline_folder_set_property;
        object_class->get_property = offline_folder_get_property;
-       object_class->dispose = offline_folder_dispose;
        object_class->finalize = offline_folder_finalize;
 
-       folder_class = CAMEL_FOLDER_CLASS (class);
-       folder_class->thaw = offline_folder_thaw;
-
        class->downsync_sync = offline_folder_downsync_sync;
 
        g_object_class_install_property (
@@ -653,9 +494,7 @@ camel_offline_folder_init (CamelOfflineFolder *folder)
 {
        folder->priv = camel_offline_folder_get_instance_private (folder);
 
-       g_mutex_init (&folder->priv->store_changes_lock);
        g_mutex_init (&folder->priv->ongoing_downloads_lock);
-       folder->priv->store_changes_after_frozen = FALSE;
        folder->priv->offline_sync = CAMEL_THREE_STATE_INCONSISTENT;
        folder->priv->ongoing_downloads = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) 
camel_pstring_free, NULL);
 
diff --git a/src/camel/camel-offline-settings.c b/src/camel/camel-offline-settings.c
index ab41ffcb2..aeba9553b 100644
--- a/src/camel/camel-offline-settings.c
+++ b/src/camel/camel-offline-settings.c
@@ -24,7 +24,6 @@
 
 struct _CamelOfflineSettingsPrivate {
        gboolean stay_synchronized;
-       gint store_changes_interval;
        gboolean limit_by_age;
        CamelTimeUnit limit_unit;
        gint limit_value;
@@ -33,7 +32,6 @@ struct _CamelOfflineSettingsPrivate {
 enum {
        PROP_0,
        PROP_STAY_SYNCHRONIZED,
-       PROP_STORE_CHANGES_INTERVAL,
        PROP_LIMIT_BY_AGE,
        PROP_LIMIT_UNIT,
        PROP_LIMIT_VALUE
@@ -57,12 +55,6 @@ offline_settings_set_property (GObject *object,
                                g_value_get_boolean (value));
                        return;
 
-               case PROP_STORE_CHANGES_INTERVAL:
-                       camel_offline_settings_set_store_changes_interval (
-                               CAMEL_OFFLINE_SETTINGS (object),
-                               g_value_get_int (value));
-                       return;
-
                case PROP_LIMIT_BY_AGE:
                        camel_offline_settings_set_limit_by_age (
                                CAMEL_OFFLINE_SETTINGS (object),
@@ -99,13 +91,6 @@ offline_settings_get_property (GObject *object,
                                CAMEL_OFFLINE_SETTINGS (object)));
                        return;
 
-               case PROP_STORE_CHANGES_INTERVAL:
-                       g_value_set_int (
-                               value,
-                               camel_offline_settings_get_store_changes_interval (
-                               CAMEL_OFFLINE_SETTINGS (object)));
-                       return;
-
                case PROP_LIMIT_BY_AGE:
                        g_value_set_boolean (
                                value,
@@ -153,21 +138,6 @@ camel_offline_settings_class_init (CamelOfflineSettingsClass *class)
                        G_PARAM_EXPLICIT_NOTIFY |
                        G_PARAM_STATIC_STRINGS));
 
-       g_object_class_install_property (
-               object_class,
-               PROP_STORE_CHANGES_INTERVAL,
-               g_param_spec_int (
-                       "store-changes-interval",
-                       "Store Changes Interval",
-                       "Interval, in seconds, to store folder changes",
-                       G_MININT,
-                       G_MAXINT,
-                       3,
-                       G_PARAM_READWRITE |
-                       G_PARAM_CONSTRUCT |
-                       G_PARAM_EXPLICIT_NOTIFY |
-                       G_PARAM_STATIC_STRINGS));
-
        g_object_class_install_property (
                object_class,
                PROP_LIMIT_BY_AGE,
@@ -261,6 +231,7 @@ camel_offline_settings_set_stay_synchronized (CamelOfflineSettings *settings,
 
        g_object_notify (G_OBJECT (settings), "stay-synchronized");
 }
+
 /**
  * camel_offline_settings_get_store_changes_interval:
  * @settings: a #CamelOfflineSettings
@@ -272,14 +243,15 @@ camel_offline_settings_set_stay_synchronized (CamelOfflineSettings *settings,
  * Returns: the interval for automatic store of folder changes
  *
  * Since: 3.18
+ *
+ * Deprecated: 3.40: Use camel_store_settings_get_store_changes_interval() instead
  **/
-
 gint
 camel_offline_settings_get_store_changes_interval (CamelOfflineSettings *settings)
 {
        g_return_val_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings), -1);
 
-       return settings->priv->store_changes_interval;
+       return camel_store_settings_get_store_changes_interval (CAMEL_STORE_SETTINGS (settings));
 }
 
 /**
@@ -292,6 +264,8 @@ camel_offline_settings_get_store_changes_interval (CamelOfflineSettings *setting
  * automatic folder change saving.
  *
  * Since: 3.18
+ *
+ * Deprecated: 3.40: Use camel_store_settings_set_store_changes_interval() instead
  **/
 void
 camel_offline_settings_set_store_changes_interval (CamelOfflineSettings *settings,
@@ -299,12 +273,7 @@ camel_offline_settings_set_store_changes_interval (CamelOfflineSettings *setting
 {
        g_return_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings));
 
-       if (settings->priv->store_changes_interval == interval)
-               return;
-
-       settings->priv->store_changes_interval = interval;
-
-       g_object_notify (G_OBJECT (settings), "store-changes-interval");
+       camel_store_settings_set_store_changes_interval (CAMEL_STORE_SETTINGS (settings), interval);
 }
 
 /**
diff --git a/src/camel/camel-offline-settings.h b/src/camel/camel-offline-settings.h
index 41e84dfc5..68e3eb10b 100644
--- a/src/camel/camel-offline-settings.h
+++ b/src/camel/camel-offline-settings.h
@@ -78,11 +78,13 @@ gboolean    camel_offline_settings_get_stay_synchronized
 void           camel_offline_settings_set_stay_synchronized
                                        (CamelOfflineSettings *settings,
                                         gboolean stay_synchronized);
+#ifndef EDS_DISABLE_DEPRECATED
 gint           camel_offline_settings_get_store_changes_interval
                                        (CamelOfflineSettings *settings);
 void           camel_offline_settings_set_store_changes_interval
                                        (CamelOfflineSettings *settings,
                                         gint interval);
+#endif /* EDS_DISABLE_DEPRECATED */
 gboolean       camel_offline_settings_get_limit_by_age
                                        (CamelOfflineSettings *settings);
 void           camel_offline_settings_set_limit_by_age
diff --git a/src/camel/camel-offline-store.c b/src/camel/camel-offline-store.c
index d58c3e2de..981a4d12e 100644
--- a/src/camel/camel-offline-store.c
+++ b/src/camel/camel-offline-store.c
@@ -110,6 +110,24 @@ offline_store_downsync_folders_thread (CamelSession *session,
        offline_store_downsync_folders_sync (store, cancellable, error);
 }
 
+static gboolean
+offline_store_get_can_auto_save_changes (CamelStore *store)
+{
+       CamelSession *session;
+       gboolean res;
+
+       g_return_val_if_fail (CAMEL_IS_OFFLINE_STORE (store), FALSE);
+
+       session = camel_service_ref_session (CAMEL_SERVICE (store));
+
+       res = session && camel_session_get_online (session) &&
+               camel_offline_store_get_online (CAMEL_OFFLINE_STORE (store));
+
+       g_clear_object (&session);
+
+       return res;
+}
+
 static void
 offline_store_constructed (GObject *object)
 {
@@ -164,6 +182,7 @@ camel_offline_store_class_init (CamelOfflineStoreClass *class)
 {
        GObjectClass *object_class;
        CamelServiceClass *service_class;
+       CamelStoreClass *store_class;
 
        object_class = G_OBJECT_CLASS (class);
        object_class->constructed = offline_store_constructed;
@@ -173,6 +192,9 @@ camel_offline_store_class_init (CamelOfflineStoreClass *class)
        service_class = CAMEL_SERVICE_CLASS (class);
        service_class->settings_type = CAMEL_TYPE_OFFLINE_SETTINGS;
 
+       store_class = CAMEL_STORE_CLASS (class);
+       store_class->get_can_auto_save_changes = offline_store_get_can_auto_save_changes;
+
        g_object_class_install_property (
                object_class,
                PROP_ONLINE,
diff --git a/src/camel/camel-store-settings.c b/src/camel/camel-store-settings.c
index 1dc49d7ec..ec831d813 100644
--- a/src/camel/camel-store-settings.c
+++ b/src/camel/camel-store-settings.c
@@ -19,11 +19,13 @@
 
 struct _CamelStoreSettingsPrivate {
        gboolean filter_inbox;
+       gint store_changes_interval;
 };
 
 enum {
        PROP_0,
-       PROP_FILTER_INBOX
+       PROP_FILTER_INBOX,
+       PROP_STORE_CHANGES_INTERVAL
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (
@@ -43,6 +45,12 @@ store_settings_set_property (GObject *object,
                                CAMEL_STORE_SETTINGS (object),
                                g_value_get_boolean (value));
                        return;
+
+               case PROP_STORE_CHANGES_INTERVAL:
+                       camel_store_settings_set_store_changes_interval (
+                               CAMEL_STORE_SETTINGS (object),
+                               g_value_get_int (value));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -61,6 +69,13 @@ store_settings_get_property (GObject *object,
                                camel_store_settings_get_filter_inbox (
                                CAMEL_STORE_SETTINGS (object)));
                        return;
+
+               case PROP_STORE_CHANGES_INTERVAL:
+                       g_value_set_int (
+                               value,
+                               camel_store_settings_get_store_changes_interval (
+                               CAMEL_STORE_SETTINGS (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -87,6 +102,21 @@ camel_store_settings_class_init (CamelStoreSettingsClass *class)
                        G_PARAM_CONSTRUCT |
                        G_PARAM_EXPLICIT_NOTIFY |
                        G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_STORE_CHANGES_INTERVAL,
+               g_param_spec_int (
+                       "store-changes-interval",
+                       "Store Changes Interval",
+                       "Interval, in seconds, to store folder changes",
+                       G_MININT,
+                       G_MAXINT,
+                       3,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_EXPLICIT_NOTIFY |
+                       G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -137,3 +167,48 @@ camel_store_settings_set_filter_inbox (CamelStoreSettings *settings,
 
        g_object_notify (G_OBJECT (settings), "filter-inbox");
 }
+
+/**
+ * camel_store_settings_get_store_changes_interval:
+ * @settings: a #CamelStoreSettings
+ *
+ * Returns the interval, in seconds, for the changes in the folder being
+ * saved automatically. 0 means immediately, while -1 means turning off
+ * automatic folder change saving.
+ *
+ * Returns: the interval for automatic store of folder changes
+ *
+ * Since: 3.40
+ **/
+gint
+camel_store_settings_get_store_changes_interval (CamelStoreSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_STORE_SETTINGS (settings), -1);
+
+       return settings->priv->store_changes_interval;
+}
+
+/**
+ * camel_store_settings_set_store_changes_interval:
+ * @settings: a #CamelStoreSettings
+ * @interval: the interval, in seconds
+ *
+ * Sets the interval, in seconds, for the changes in the folder being
+ * saved automatically. 0 means immediately, while -1 means turning off
+ * automatic folder change saving.
+ *
+ * Since: 3.40
+ **/
+void
+camel_store_settings_set_store_changes_interval (CamelStoreSettings *settings,
+                                                gint interval)
+{
+       g_return_if_fail (CAMEL_IS_STORE_SETTINGS (settings));
+
+       if (settings->priv->store_changes_interval == interval)
+               return;
+
+       settings->priv->store_changes_interval = interval;
+
+       g_object_notify (G_OBJECT (settings), "store-changes-interval");
+}
diff --git a/src/camel/camel-store-settings.h b/src/camel/camel-store-settings.h
index 010fa8692..fe9ec164a 100644
--- a/src/camel/camel-store-settings.h
+++ b/src/camel/camel-store-settings.h
@@ -76,6 +76,11 @@ gboolean     camel_store_settings_get_filter_inbox
 void           camel_store_settings_set_filter_inbox
                                                (CamelStoreSettings *settings,
                                                 gboolean filter_inbox);
+gint           camel_store_settings_get_store_changes_interval
+                                               (CamelStoreSettings *settings);
+void           camel_store_settings_set_store_changes_interval
+                                               (CamelStoreSettings *settings,
+                                                gint interval);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-store.c b/src/camel/camel-store.c
index 71c4ea7f4..844ac0517 100644
--- a/src/camel/camel-store.c
+++ b/src/camel/camel-store.c
@@ -557,6 +557,12 @@ store_initable_init (GInitable *initable,
        return TRUE;
 }
 
+static gboolean
+store_get_can_auto_save_changes (CamelStore *store)
+{
+       return TRUE;
+}
+
 static void
 camel_store_class_init (CamelStoreClass *class)
 {
@@ -580,6 +586,7 @@ camel_store_class_init (CamelStoreClass *class)
        class->get_trash_folder_sync = store_get_trash_folder_sync;
        class->synchronize_sync = store_synchronize_sync;
        class->initial_setup_sync = store_initial_setup_sync;
+       class->get_can_auto_save_changes = store_get_can_auto_save_changes;
 
        signals[FOLDER_CREATED] = g_signal_new (
                "folder-created",
@@ -3327,3 +3334,27 @@ camel_store_delete_cached_folder (CamelStore *store,
        camel_object_bag_remove (store->priv->folders, folder);
        g_object_unref (folder);
 }
+
+/**
+ * camel_store_get_can_auto_save_changes:
+ * @store: a #CamelStore
+ *
+ * Returns whether there can be done automatic save of folder changes.
+ * Default is TRUE. The descendants can overwrite it with CamelStoreClass::get_can_auto_save_changes().
+ *
+ * Return: Whether there can be done automatic save of folder changes.
+ *
+ * Since: 3.40
+ **/
+gboolean
+camel_store_get_can_auto_save_changes (CamelStore *store)
+{
+       CamelStoreClass *klass;
+
+       g_return_val_if_fail (CAMEL_IS_STORE (store), FALSE);
+
+       klass = CAMEL_STORE_GET_CLASS (store);
+       g_return_val_if_fail (klass != NULL, FALSE);
+
+       return klass->get_can_auto_save_changes && klass->get_can_auto_save_changes (store);
+}
diff --git a/src/camel/camel-store.h b/src/camel/camel-store.h
index 45c309ebf..76e2b791b 100644
--- a/src/camel/camel-store.h
+++ b/src/camel/camel-store.h
@@ -206,9 +206,11 @@ struct _CamelStoreClass {
                                                 GHashTable *out_save_setup,
                                                 GCancellable *cancellable,
                                                 GError **error);
+       gboolean        (*get_can_auto_save_changes)
+                                               (CamelStore *store);
 
        /* Padding for future expansion */
-       gpointer reserved_methods[20];
+       gpointer reserved_methods[19];
 
        /* Signals */
        void            (*folder_created)       (CamelStore *store,
@@ -416,6 +418,8 @@ gboolean    camel_store_maybe_run_db_maintenance
 void           camel_store_delete_cached_folder
                                                (CamelStore *store,
                                                 const gchar *folder_name);
+gboolean       camel_store_get_can_auto_save_changes
+                                               (CamelStore *store);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-vee-store.c b/src/camel/camel-vee-store.c
index a8414b210..09bac5e4e 100644
--- a/src/camel/camel-vee-store.c
+++ b/src/camel/camel-vee-store.c
@@ -514,6 +514,13 @@ vee_store_rename_folder_sync (CamelStore *store,
        return TRUE;
 }
 
+static gboolean
+vee_store_get_can_auto_save_changes (CamelStore *store)
+{
+       /* Let only the real folder auto-save the changes */
+       return FALSE;
+}
+
 static void
 camel_vee_store_class_init (CamelVeeStoreClass *class)
 {
@@ -538,6 +545,7 @@ camel_vee_store_class_init (CamelVeeStoreClass *class)
        store_class->get_trash_folder_sync = vee_store_get_trash_folder_sync;
        store_class->delete_folder_sync = vee_store_delete_folder_sync;
        store_class->rename_folder_sync = vee_store_rename_folder_sync;
+       store_class->get_can_auto_save_changes = vee_store_get_can_auto_save_changes;
 
        g_object_class_install_property (
                object_class,


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]