[evolution-data-server] Bug 773419 - Age limit for offline message download



commit e62b124811cb6c0c169f771773e4a0d2ef06f95e
Author: Milan Crha <mcrha redhat com>
Date:   Mon Dec 12 22:22:10 2016 +0100

    Bug 773419 - Age limit for offline message download

 src/camel/camel-enums.h                          |   22 ++-
 src/camel/camel-offline-folder.c                 |   93 +++++++++-
 src/camel/camel-offline-settings.c               |  213 +++++++++++++++++++++-
 src/camel/camel-offline-settings.h               |   16 ++
 src/camel/camel-utils.c                          |   71 +++++++
 src/camel/camel-utils.h                          |    6 +
 src/camel/providers/imapx/camel-imapx-provider.c |    1 +
 7 files changed, 411 insertions(+), 11 deletions(-)
---
diff --git a/src/camel/camel-enums.h b/src/camel/camel-enums.h
index 3e3bb9a..2900971 100644
--- a/src/camel/camel-enums.h
+++ b/src/camel/camel-enums.h
@@ -336,7 +336,8 @@ typedef enum {
        CAMEL_PROVIDER_CONF_ENTRY,
        CAMEL_PROVIDER_CONF_LABEL,
        CAMEL_PROVIDER_CONF_HIDDEN,
-       CAMEL_PROVIDER_CONF_OPTIONS
+       CAMEL_PROVIDER_CONF_OPTIONS,
+       CAMEL_PROVIDER_CONF_PLACEHOLDER
 } CamelProviderConfType;
 
 /**
@@ -531,4 +532,23 @@ typedef enum {
        CAMEL_COMPARE_CASE_SENSITIVE
 } CamelCompareType;
 
+/**
+ * CamelTimeUnit:
+ * @CAMEL_TIME_UNIT_DAYS: days
+ * @CAMEL_TIME_UNIT_WEEKS: weeks
+ * @CAMEL_TIME_UNIT_MONTHS: months
+ * @CAMEL_TIME_UNIT_YEARS: years
+ *
+ * Declares time unit, which serves to interpret the time value,
+ * like in #CamelOfflineSettings.
+ *
+ * Since: 3.24
+ **/
+typedef enum {
+       CAMEL_TIME_UNIT_DAYS = 1,
+       CAMEL_TIME_UNIT_WEEKS,
+       CAMEL_TIME_UNIT_MONTHS,
+       CAMEL_TIME_UNIT_YEARS
+} CamelTimeUnit;
+
 #endif /* CAMEL_ENUMS_H */
diff --git a/src/camel/camel-offline-folder.c b/src/camel/camel-offline-folder.c
index 8edac3b..a29557f 100644
--- a/src/camel/camel-offline-folder.c
+++ b/src/camel/camel-offline-folder.c
@@ -28,6 +28,7 @@
 #include "camel-offline-store.h"
 #include "camel-operation.h"
 #include "camel-session.h"
+#include "camel-utils.h"
 
 #define CAMEL_OFFLINE_FOLDER_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -81,12 +82,42 @@ offline_downsync_data_free (OfflineDownsyncData *data)
        g_slice_free (OfflineDownsyncData, data);
 }
 
+/* Returns 0, if not set any limit */
+static gint64
+offline_folder_get_limit_time (CamelFolder *folder)
+{
+       CamelStore *parent_store;
+       CamelSettings *settings;
+       gint64 limit_time = 0;
+
+       g_return_val_if_fail (CAMEL_IS_FOLDER (folder), -1);
+
+       parent_store = camel_folder_get_parent_store (folder);
+       if (!parent_store)
+               return limit_time;
+
+       settings = camel_service_ref_settings (CAMEL_SERVICE (parent_store));
+
+       if (CAMEL_IS_OFFLINE_SETTINGS (settings) &&
+           camel_offline_settings_get_limit_by_age (CAMEL_OFFLINE_SETTINGS (settings))) {
+               limit_time = camel_time_value_apply (-1,
+                       camel_offline_settings_get_limit_unit (CAMEL_OFFLINE_SETTINGS (settings)),
+                       -camel_offline_settings_get_limit_value (CAMEL_OFFLINE_SETTINGS (settings)));
+       }
+
+       g_clear_object (&settings);
+
+       return limit_time;
+}
+
 static void
 offline_folder_downsync_background (CamelSession *session,
                                     GCancellable *cancellable,
                                     OfflineDownsyncData *data,
                                     GError **error)
 {
+       gint64 limit_time;
+
        camel_operation_push_message (
                /* 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
@@ -95,6 +126,8 @@ offline_folder_downsync_background (CamelSession *session,
                camel_service_get_display_name (CAMEL_SERVICE (camel_folder_get_parent_store (data->folder))),
                camel_folder_get_full_name (data->folder));
 
+       limit_time = offline_folder_get_limit_time (data->folder);
+
        if (data->changes) {
                GPtrArray *uid_added;
                gboolean success = TRUE;
@@ -111,13 +144,36 @@ offline_folder_downsync_background (CamelSession *session,
 
                        camel_operation_progress (cancellable, percent);
 
+                       if (limit_time > 0) {
+                               CamelMessageInfo *mi;
+                               gboolean download;
+
+                               mi = camel_folder_get_message_info (data->folder, uid);
+                               if (!mi)
+                                       continue;
+
+                               download = camel_message_info_get_date_sent (mi) > limit_time;
+
+                               g_clear_object (&mi);
+
+                               if (!download)
+                                       continue;
+                       }
+
                        success = camel_folder_synchronize_message_sync (
                                data->folder, uid, cancellable, error);
                }
        } else {
+               gchar *expression = NULL;
+
+               if (limit_time > 0)
+                       expression = g_strdup_printf ("(match-all (> (get-sent-date) %" G_GINT64_FORMAT ")", 
limit_time);
+
                camel_offline_folder_downsync_sync (
                        CAMEL_OFFLINE_FOLDER (data->folder),
-                       "(match-all)", cancellable, error);
+                       expression ? expression : "(match-all)", cancellable, error);
+
+               g_free (expression);
        }
 
        camel_operation_pop_message (cancellable);
@@ -363,6 +419,7 @@ offline_folder_downsync_sync (CamelOfflineFolder *offline,
 {
        CamelFolder *folder = (CamelFolder *) offline;
        GPtrArray *uids, *uncached_uids = NULL;
+       gint64 limit_time;
        gint i;
 
        /* Translators: The first “%s” is replaced with an account name and the second “%s”
@@ -390,14 +447,36 @@ offline_folder_downsync_sync (CamelOfflineFolder *offline,
        if (!uncached_uids)
                goto done;
 
-       for (i = 0; i < uncached_uids->len; i++) {
-               camel_folder_synchronize_message_sync (
-                       folder, uncached_uids->pdata[i], cancellable, NULL);
-               camel_operation_progress (
-                       cancellable, i * 100 / uncached_uids->len);
+       limit_time = offline_folder_get_limit_time (folder);
+       if (limit_time > 0 && camel_folder_get_folder_summary (folder))
+               camel_folder_summary_prepare_fetch_all (camel_folder_get_folder_summary (folder), NULL);
+
+       for (i = 0; i < uncached_uids->len && !g_cancellable_is_cancelled (cancellable); i++) {
+               const gchar *uid = uncached_uids->pdata[i];
+               gboolean download = limit_time <= 0;
+
+               if (limit_time > 0) {
+                       CamelMessageInfo *mi;
+
+                       mi = camel_folder_get_message_info (folder, uid);
+                       if (!mi)
+                               continue;
+
+                       download = camel_message_info_get_date_sent (mi) > limit_time;
+
+                       g_clear_object (&mi);
+               }
+
+               if (download) {
+                       /* Stop on failure */
+                       if (!camel_folder_synchronize_message_sync (folder, uid, cancellable, NULL))
+                               break;
+               }
+
+               camel_operation_progress (cancellable, i * 100 / uncached_uids->len);
        }
 
-done:
+ done:
        if (uncached_uids)
                camel_folder_free_uids (folder, uncached_uids);
 
diff --git a/src/camel/camel-offline-settings.c b/src/camel/camel-offline-settings.c
index 8b4aa6e..04dab33 100644
--- a/src/camel/camel-offline-settings.c
+++ b/src/camel/camel-offline-settings.c
@@ -15,9 +15,12 @@
  *
  */
 
-#include "camel-offline-settings.h"
+#include "evolution-data-server-config.h"
+
+#include "camel-store-settings.h"
+#include "camel-enumtypes.h"
 
-#include <camel/camel-store-settings.h>
+#include "camel-offline-settings.h"
 
 #define CAMEL_OFFLINE_SETTINGS_GET_PRIVATE(obj) \
        (G_TYPE_INSTANCE_GET_PRIVATE \
@@ -26,12 +29,18 @@
 struct _CamelOfflineSettingsPrivate {
        gboolean stay_synchronized;
        gint store_changes_interval;
+       gboolean limit_by_age;
+       CamelTimeUnit limit_unit;
+       gint limit_value;
 };
 
 enum {
        PROP_0,
        PROP_STAY_SYNCHRONIZED,
-       PROP_STORE_CHANGES_INTERVAL
+       PROP_STORE_CHANGES_INTERVAL,
+       PROP_LIMIT_BY_AGE,
+       PROP_LIMIT_UNIT,
+       PROP_LIMIT_VALUE
 };
 
 G_DEFINE_TYPE (
@@ -57,6 +66,24 @@ offline_settings_set_property (GObject *object,
                                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),
+                               g_value_get_boolean (value));
+                       return;
+
+               case PROP_LIMIT_UNIT:
+                       camel_offline_settings_set_limit_unit (
+                               CAMEL_OFFLINE_SETTINGS (object),
+                               g_value_get_enum (value));
+                       return;
+
+               case PROP_LIMIT_VALUE:
+                       camel_offline_settings_set_limit_value (
+                               CAMEL_OFFLINE_SETTINGS (object),
+                               g_value_get_int (value));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -82,6 +109,27 @@ offline_settings_get_property (GObject *object,
                                camel_offline_settings_get_store_changes_interval (
                                CAMEL_OFFLINE_SETTINGS (object)));
                        return;
+
+               case PROP_LIMIT_BY_AGE:
+                       g_value_set_boolean (
+                               value,
+                               camel_offline_settings_get_limit_by_age (
+                               CAMEL_OFFLINE_SETTINGS (object)));
+                       return;
+
+               case PROP_LIMIT_UNIT:
+                       g_value_set_enum (
+                               value,
+                               camel_offline_settings_get_limit_unit (
+                               CAMEL_OFFLINE_SETTINGS (object)));
+                       return;
+
+               case PROP_LIMIT_VALUE:
+                       g_value_set_int (
+                               value,
+                               camel_offline_settings_get_limit_value (
+                               CAMEL_OFFLINE_SETTINGS (object)));
+                       return;
        }
 
        G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -123,6 +171,45 @@ camel_offline_settings_class_init (CamelOfflineSettingsClass *class)
                        G_PARAM_READWRITE |
                        G_PARAM_CONSTRUCT |
                        G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_LIMIT_BY_AGE,
+               g_param_spec_boolean (
+                       "limit-by-age",
+                       "Limit By Age",
+                       "Whether to limit what will be synchronized by message date",
+                       FALSE,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_LIMIT_UNIT,
+               g_param_spec_enum (
+                       "limit-unit",
+                       "Limit Unit",
+                       "A unit for the limit-value",
+                       CAMEL_TYPE_TIME_UNIT,
+                       CAMEL_TIME_UNIT_YEARS,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
+
+       g_object_class_install_property (
+               object_class,
+               PROP_LIMIT_VALUE,
+               g_param_spec_int (
+                       "limit-value",
+                       "Limit Value",
+                       "How many days/weeks/months/years to download into the local cache, if limit-by-age 
is set to TRUE",
+                       1,
+                       G_MAXINT,
+                       1,
+                       G_PARAM_READWRITE |
+                       G_PARAM_CONSTRUCT |
+                       G_PARAM_STATIC_STRINGS));
 }
 
 static void
@@ -220,3 +307,123 @@ camel_offline_settings_set_store_changes_interval (CamelOfflineSettings *setting
 
        g_object_notify (G_OBJECT (settings), "store-changes-interval");
 }
+
+/**
+ * camel_offline_settings_get_limit_by_age:
+ * @settings: a #CamelOfflineSettings
+ *
+ * Returns: whether limit messages stored for offline use by their age
+ *
+ * Since: 3.24
+ **/
+gboolean
+camel_offline_settings_get_limit_by_age (CamelOfflineSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings), FALSE);
+
+       return settings->priv->limit_by_age;
+}
+
+/**
+ * camel_offline_settings_set_limit_by_age:
+ * @settings: a #CamelOfflineSettings
+ * @limit_by_age: a value to set
+ *
+ * Set whether the messages to download for offline should be limited
+ * by age. If set to %TRUE, then messages older than 'limit-value'
+ * will not be downloaded automatically.
+ *
+ * Since: 3.24
+ **/
+void
+camel_offline_settings_set_limit_by_age (CamelOfflineSettings *settings,
+                                        gboolean limit_by_age)
+{
+       g_return_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings));
+
+       if ((!settings->priv->limit_by_age) == (!limit_by_age))
+               return;
+
+       settings->priv->limit_by_age = limit_by_age;
+
+       g_object_notify (G_OBJECT (settings), "limit-by-age");
+}
+
+/**
+ * camel_offline_settings_get_limit_unit:
+ * @settings: a #CamelOfflineSettings
+ *
+ * Returns: the limit unit to use when interpreting 'limit-value'
+ *
+ * Since: 3.24
+ **/
+CamelTimeUnit
+camel_offline_settings_get_limit_unit (CamelOfflineSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings), CAMEL_TIME_UNIT_YEARS);
+
+       return settings->priv->limit_unit;
+}
+
+/**
+ * camel_offline_settings_set_limit_unit:
+ * @settings: a #CamelOfflineSettings
+ * @limit_unit: a #CamelTimeUnit with a unit to use
+ *
+ * Set the limit unit to use when interpreting 'limit-value'.
+ *
+ * Since: 3.24
+ **/
+void
+camel_offline_settings_set_limit_unit (CamelOfflineSettings *settings,
+                                      CamelTimeUnit limit_unit)
+{
+       g_return_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings));
+       g_return_if_fail (limit_unit >= CAMEL_TIME_UNIT_DAYS && limit_unit <= CAMEL_TIME_UNIT_YEARS);
+
+       if (settings->priv->limit_unit == limit_unit)
+               return;
+
+       settings->priv->limit_unit = limit_unit;
+
+       g_object_notify (G_OBJECT (settings), "limit-unit");
+}
+
+/**
+ * camel_offline_settings_get_limit_value:
+ * @settings: a #CamelOfflineSettings
+ *
+ * Returns: the limit, in 'limit-unit', to use when 'limit-by-age' is set to %TRUE
+ *
+ * Since: 3.24
+ **/
+gint
+camel_offline_settings_get_limit_value (CamelOfflineSettings *settings)
+{
+       g_return_val_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings), -1);
+
+       return settings->priv->limit_value;
+}
+
+/**
+ * camel_offline_settings_set_limit_value:
+ * @settings: a #CamelOfflineSettings
+ * @limit_value: a value to set
+ *
+ * Set the limit, in 'limit-unit', to use when 'limit-by-age' is set to %TRUE.
+ *
+ * Since: 3.24
+ **/
+void
+camel_offline_settings_set_limit_value (CamelOfflineSettings *settings,
+                                       gboolean limit_value)
+{
+       g_return_if_fail (CAMEL_IS_OFFLINE_SETTINGS (settings));
+
+       if (settings->priv->limit_value == limit_value)
+               return;
+
+       settings->priv->limit_value = limit_value;
+
+       g_object_notify (G_OBJECT (settings), "limit-value");
+}
diff --git a/src/camel/camel-offline-settings.h b/src/camel/camel-offline-settings.h
index 63452a0..41e84df 100644
--- a/src/camel/camel-offline-settings.h
+++ b/src/camel/camel-offline-settings.h
@@ -22,6 +22,7 @@
 #ifndef CAMEL_OFFLINE_SETTINGS_H
 #define CAMEL_OFFLINE_SETTINGS_H
 
+#include <camel/camel-enums.h>
 #include <camel/camel-store-settings.h>
 
 /* Standard GObject macros */
@@ -82,6 +83,21 @@ gint         camel_offline_settings_get_store_changes_interval
 void           camel_offline_settings_set_store_changes_interval
                                        (CamelOfflineSettings *settings,
                                         gint interval);
+gboolean       camel_offline_settings_get_limit_by_age
+                                       (CamelOfflineSettings *settings);
+void           camel_offline_settings_set_limit_by_age
+                                       (CamelOfflineSettings *settings,
+                                        gboolean limit_by_age);
+CamelTimeUnit  camel_offline_settings_get_limit_unit
+                                       (CamelOfflineSettings *settings);
+void           camel_offline_settings_set_limit_unit
+                                       (CamelOfflineSettings *settings,
+                                        CamelTimeUnit limit_unit);
+gint           camel_offline_settings_get_limit_value
+                                       (CamelOfflineSettings *settings);
+void           camel_offline_settings_set_limit_value
+                                       (CamelOfflineSettings *settings,
+                                        gboolean limit_value);
 
 G_END_DECLS
 
diff --git a/src/camel/camel-utils.c b/src/camel/camel-utils.c
index b7a0f5d..b38b9a9 100644
--- a/src/camel/camel-utils.c
+++ b/src/camel/camel-utils.c
@@ -171,3 +171,74 @@ camel_util_bdata_put_string (GString *bdata_str,
 
        g_string_append_printf (bdata_str, "-%s", value);
 }
+
+/**
+ * camel_time_value_apply:
+ * @src_time: a time_t to apply the value to, or -1 to use the current time
+ * @unit: a #CamelTimeUnit
+ * @value: a value to apply
+ *
+ * Applies the given time @value in unit @unit to the @src_time.
+ * Use negative value to subtract it. The time part is rounded
+ * to the beginning of the day.
+ *
+ * Returns: @src_time modified by the given parameters as date, with
+ *    the time part being beginning of the day.
+ *
+ * Since: 3.24
+ **/
+time_t
+camel_time_value_apply (time_t src_time,
+                       CamelTimeUnit unit,
+                       gint value)
+{
+       GDate dt;
+       struct tm tm;
+
+       g_return_val_if_fail (unit >= CAMEL_TIME_UNIT_DAYS && unit <= CAMEL_TIME_UNIT_YEARS, src_time);
+
+       if (src_time == (time_t) -1)
+               src_time = time (NULL);
+
+       if (!value)
+               return src_time;
+
+       g_date_clear (&dt, 1);
+
+       g_date_set_time_t (&dt, src_time);
+
+       switch (unit) {
+       case CAMEL_TIME_UNIT_DAYS:
+               if (value > 0)
+                       g_date_add_days (&dt, value);
+               else
+                       g_date_subtract_days (&dt, (-1) * value);
+               break;
+       case CAMEL_TIME_UNIT_WEEKS:
+               if (value > 0)
+                       g_date_add_days (&dt, value * 7);
+               else
+                       g_date_subtract_days (&dt, (-1) * value * 7);
+               break;
+       case CAMEL_TIME_UNIT_MONTHS:
+               if (value > 0)
+                       g_date_add_months (&dt, value);
+               else
+                       g_date_subtract_months (&dt, (-1) * value);
+               break;
+       case CAMEL_TIME_UNIT_YEARS:
+               if (value > 0)
+                       g_date_add_years (&dt, value);
+               else
+                       g_date_subtract_years (&dt, (-1) * value);
+               break;
+       }
+
+       g_date_to_struct_tm (&dt, &tm);
+
+       tm.tm_sec = 0;
+       tm.tm_min = 0;
+       tm.tm_hour = 0;
+
+       return mktime (&tm);
+}
diff --git a/src/camel/camel-utils.h b/src/camel/camel-utils.h
index 25c2864..c256057 100644
--- a/src/camel/camel-utils.h
+++ b/src/camel/camel-utils.h
@@ -23,6 +23,8 @@
 #define CAMEL_UTILS_H
 
 #include <glib-object.h>
+#include <time.h>
+#include <camel/camel-enums.h>
 
 G_BEGIN_DECLS
 
@@ -35,6 +37,10 @@ gchar *              camel_util_bdata_get_string     (/* const */ gchar **bdata_ptr,
 void           camel_util_bdata_put_string     (GString *bdata_str,
                                                 const gchar *value);
 
+time_t         camel_time_value_apply          (time_t src_time,
+                                                CamelTimeUnit unit,
+                                                gint value);
+
 G_END_DECLS
 
 #endif /* CAMEL_UTILS_H */
diff --git a/src/camel/providers/imapx/camel-imapx-provider.c 
b/src/camel/providers/imapx/camel-imapx-provider.c
index 9036364..0b1d432 100644
--- a/src/camel/providers/imapx/camel-imapx-provider.c
+++ b/src/camel/providers/imapx/camel-imapx-provider.c
@@ -70,6 +70,7 @@ CamelProviderConfEntry imapx_conf_entries[] = {
          N_("Only check for Junk messages in the In_box folder"), "0" },
        { CAMEL_PROVIDER_CONF_CHECKBOX, "stay-synchronized", NULL,
          N_("Synchroni_ze remote mail locally in all folders"), "0" },
+       { CAMEL_PROVIDER_CONF_PLACEHOLDER, "imapx-limit-by-age-placeholder", NULL },
        { CAMEL_PROVIDER_CONF_SECTION_END },
        { CAMEL_PROVIDER_CONF_END }
 };


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