summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2023-03-31 09:30:01 +0200
committerMilan Crha <mcrha@redhat.com>2023-03-31 09:30:01 +0200
commit698b97b60401f75280e8b1ecb0e3770159966dfa (patch)
tree715a737447eaecbf7366f1e40a78334556863b35
parent976fee2ff85fc94c1bc5cc925ca7a2e2ad131297 (diff)
downloadevolution-data-server-698b97b60401f75280e8b1ecb0e3770159966dfa.tar.gz
IMAPX: Add option for "Single client mode"
The "Single client mode" is enabled by default and it means that full folder update (check of flags on old messages) is done only once per day, which can save bandwidth and time significantly.
-rw-r--r--docs/reference/camel/camel-docs.sgml.in4
-rw-r--r--src/camel/camel-file-utils.c26
-rw-r--r--src/camel/camel-file-utils.h2
-rw-r--r--src/camel/camel-object.c19
-rw-r--r--src/camel/providers/imapx/camel-imapx-folder.c53
-rw-r--r--src/camel/providers/imapx/camel-imapx-folder.h5
-rw-r--r--src/camel/providers/imapx/camel-imapx-provider.c2
-rw-r--r--src/camel/providers/imapx/camel-imapx-server.c59
-rw-r--r--src/camel/providers/imapx/camel-imapx-settings.c73
-rw-r--r--src/camel/providers/imapx/camel-imapx-settings.h5
10 files changed, 231 insertions, 17 deletions
diff --git a/docs/reference/camel/camel-docs.sgml.in b/docs/reference/camel/camel-docs.sgml.in
index 6f2304ccd..3d889b50d 100644
--- a/docs/reference/camel/camel-docs.sgml.in
+++ b/docs/reference/camel/camel-docs.sgml.in
@@ -299,6 +299,10 @@
<title>Index of deprecated symbols</title>
<xi:include href="xml/api-index-deprecated.xml"><xi:fallback /></xi:include>
</index>
+ <index id="api-index-3-50" role="3.50">
+ <title>Index of new symbols in 3.50</title>
+ <xi:include href="xml/api-index-3.50.xml"><xi:fallback /></xi:include>
+ </index>
<index id="api-index-3-46" role="3.46">
<title>Index of new symbols in 3.46</title>
<xi:include href="xml/api-index-3.46.xml"><xi:fallback /></xi:include>
diff --git a/src/camel/camel-file-utils.c b/src/camel/camel-file-utils.c
index e4b052eb9..368a3b77a 100644
--- a/src/camel/camel-file-utils.c
+++ b/src/camel/camel-file-utils.c
@@ -249,6 +249,32 @@ CFU_ENCODE_T (gsize)
CFU_DECODE_T (gsize)
/**
+ * camel_file_util_encode_gint64:
+ * @out: file to output to
+ * @value: value to output
+ *
+ * Encode a gint64 type.
+ *
+ * Returns: 0 on success, -1 on error.
+ *
+ * Since: 3.50
+ **/
+CFU_ENCODE_T (gint64)
+
+/**
+ * camel_file_util_decode_gint64:
+ * @in: file to read from
+ * @dest: pointer to a variable to put the value in
+ *
+ * Decode a gint64 type.
+ *
+ * Returns: 0 on success, -1 on failure.
+ *
+ * Since: 3.50
+ **/
+CFU_DECODE_T (gint64)
+
+/**
* camel_file_util_encode_string:
* @out: file to output to
* @str: value to output
diff --git a/src/camel/camel-file-utils.h b/src/camel/camel-file-utils.h
index 6bc4513ac..76c66d04a 100644
--- a/src/camel/camel-file-utils.h
+++ b/src/camel/camel-file-utils.h
@@ -48,6 +48,8 @@ gint camel_file_util_encode_off_t (FILE *out, off_t value);
gint camel_file_util_decode_off_t (FILE *in, off_t *dest);
gint camel_file_util_encode_gsize (FILE *out, gsize value);
gint camel_file_util_decode_gsize (FILE *in, gsize *dest);
+gint camel_file_util_encode_gint64 (FILE *out, gint64 value);
+gint camel_file_util_decode_gint64 (FILE *in, gint64 *dest);
gint camel_file_util_encode_string (FILE *out, const gchar *str);
gint camel_file_util_decode_string (FILE *in, gchar **str);
gint camel_file_util_encode_fixed_string (FILE *out, const gchar *str, gsize len);
diff --git a/src/camel/camel-object.c b/src/camel/camel-object.c
index 2c7ebd3f1..2572acf0c 100644
--- a/src/camel/camel-object.c
+++ b/src/camel/camel-object.c
@@ -81,7 +81,8 @@ enum camel_arg_t {
CAMEL_ARG_STR = 0x30000000, /* c string */
CAMEL_ARG_PTR = 0x40000000, /* ptr */
CAMEL_ARG_BOO = 0x50000000, /* bool */
- CAMEL_ARG_3ST = 0x60000000 /* three-state */
+ CAMEL_ARG_3ST = 0x60000000, /* three-state */
+ CAMEL_ARG_I64 = 0x70000000 /* gint64 */
};
#define CAMEL_ARGV_MAX (20)
@@ -197,6 +198,7 @@ object_state_read (CamelObject *object,
gboolean property_set = FALSE;
guint32 tag, v_uint32;
gint32 v_int32;
+ gint64 v_int64;
if (camel_file_util_decode_uint32 (fp, &tag) == -1)
goto exit;
@@ -222,6 +224,12 @@ object_state_read (CamelObject *object,
g_value_init (&value, CAMEL_TYPE_THREE_STATE);
g_value_set_enum (&value, (CamelThreeState) v_uint32);
break;
+ case CAMEL_ARG_I64:
+ if (camel_file_util_decode_gint64 (fp, &v_int64) == -1)
+ goto exit;
+ g_value_init (&value, G_TYPE_INT64);
+ g_value_set_int64 (&value, v_int64);
+ break;
default:
g_warn_if_reached ();
goto exit;
@@ -324,6 +332,7 @@ object_state_write (CamelObject *object,
GParamSpec *pspec = properties[ii];
guint32 tag, v_uint32;
gint32 v_int32;
+ gint64 v_int64;
if ((pspec->flags & CAMEL_PARAM_PERSISTENT) == 0)
continue;
@@ -354,6 +363,14 @@ object_state_write (CamelObject *object,
if (camel_file_util_encode_fixed_int32 (fp, v_int32) == -1)
goto exit;
break;
+ case G_TYPE_INT64:
+ tag |= CAMEL_ARG_I64;
+ v_int64 = g_value_get_int64 (&value);
+ if (camel_file_util_encode_uint32 (fp, tag) == -1)
+ goto exit;
+ if (camel_file_util_encode_gint64 (fp, v_int64) == -1)
+ goto exit;
+ break;
default:
if (pspec->value_type == CAMEL_TYPE_THREE_STATE) {
tag |= CAMEL_ARG_3ST;
diff --git a/src/camel/providers/imapx/camel-imapx-folder.c b/src/camel/providers/imapx/camel-imapx-folder.c
index 91ce26097..4a0769fee 100644
--- a/src/camel/providers/imapx/camel-imapx-folder.c
+++ b/src/camel/providers/imapx/camel-imapx-folder.c
@@ -46,6 +46,7 @@ struct _CamelIMAPXFolderPrivate {
GHashTable *move_to_inbox_uids;
gboolean check_folder;
+ gint64 last_full_update;
};
/* The custom property ID is a CamelArg artifact.
@@ -54,7 +55,8 @@ enum {
PROP_0,
PROP_MAILBOX,
PROP_APPLY_FILTERS = 0x2501,
- PROP_CHECK_FOLDER = 0x2502
+ PROP_CHECK_FOLDER = 0x2502,
+ PROP_LAST_FULL_UPDATE = 0x2503
};
G_DEFINE_TYPE_WITH_PRIVATE (CamelIMAPXFolder, camel_imapx_folder, CAMEL_TYPE_OFFLINE_FOLDER)
@@ -161,6 +163,12 @@ imapx_folder_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_LAST_FULL_UPDATE:
+ camel_imapx_folder_set_last_full_update (
+ CAMEL_IMAPX_FOLDER (object),
+ g_value_get_int64 (value));
+ return;
+
case PROP_MAILBOX:
camel_imapx_folder_set_mailbox (
CAMEL_IMAPX_FOLDER (object),
@@ -192,6 +200,13 @@ imapx_folder_get_property (GObject *object,
CAMEL_IMAPX_FOLDER (object)));
return;
+ case PROP_LAST_FULL_UPDATE:
+ g_value_set_int64 (
+ value,
+ camel_imapx_folder_get_last_full_update (
+ CAMEL_IMAPX_FOLDER (object)));
+ return;
+
case PROP_MAILBOX:
g_value_take_object (
value,
@@ -1141,6 +1156,18 @@ camel_imapx_folder_class_init (CamelIMAPXFolderClass *class)
g_object_class_install_property (
object_class,
+ PROP_LAST_FULL_UPDATE,
+ g_param_spec_int64 (
+ "last-full-update",
+ "Last Full Update",
+ NULL,
+ G_MININT64, G_MAXINT64, 0,
+ G_PARAM_READWRITE |
+ G_PARAM_EXPLICIT_NOTIFY |
+ CAMEL_PARAM_PERSISTENT));
+
+ g_object_class_install_property (
+ object_class,
PROP_MAILBOX,
g_param_spec_object (
"mailbox",
@@ -1707,6 +1734,30 @@ camel_imapx_folder_set_check_folder (CamelIMAPXFolder *folder,
g_object_notify (G_OBJECT (folder), "check-folder");
}
+gint64
+camel_imapx_folder_get_last_full_update (CamelIMAPXFolder *folder)
+{
+ g_return_val_if_fail (folder != NULL, 0);
+ g_return_val_if_fail (CAMEL_IS_IMAPX_FOLDER (folder), 0);
+
+ return folder->priv->last_full_update;
+}
+
+void
+camel_imapx_folder_set_last_full_update (CamelIMAPXFolder *folder,
+ gint64 last_full_update)
+{
+ g_return_if_fail (folder != NULL);
+ g_return_if_fail (CAMEL_IS_IMAPX_FOLDER (folder));
+
+ if (folder->priv->last_full_update == last_full_update)
+ return;
+
+ folder->priv->last_full_update = last_full_update;
+
+ g_object_notify (G_OBJECT (folder), "last-full-update");
+}
+
void
camel_imapx_folder_update_cache_expire (CamelFolder *folder,
time_t expire_when)
diff --git a/src/camel/providers/imapx/camel-imapx-folder.h b/src/camel/providers/imapx/camel-imapx-folder.h
index 1d42f7f7a..0229f3f78 100644
--- a/src/camel/providers/imapx/camel-imapx-folder.h
+++ b/src/camel/providers/imapx/camel-imapx-folder.h
@@ -102,6 +102,11 @@ gboolean camel_imapx_folder_get_check_folder
void camel_imapx_folder_set_check_folder
(CamelIMAPXFolder *folder,
gboolean check_folder);
+gint64 camel_imapx_folder_get_last_full_update
+ (CamelIMAPXFolder *folder);
+void camel_imapx_folder_set_last_full_update
+ (CamelIMAPXFolder *folder,
+ gint64 last_full_update);
void camel_imapx_folder_claim_move_to_real_junk_uids
(CamelIMAPXFolder *folder,
GPtrArray *out_uids_to_copy);
diff --git a/src/camel/providers/imapx/camel-imapx-provider.c b/src/camel/providers/imapx/camel-imapx-provider.c
index f6180bdb2..2b8f7d14b 100644
--- a/src/camel/providers/imapx/camel-imapx-provider.c
+++ b/src/camel/providers/imapx/camel-imapx-provider.c
@@ -93,6 +93,8 @@ CamelProviderConfEntry imapx_conf_entries[] = {
{ CAMEL_PROVIDER_CONF_CHECKSPIN, "store-changes-interval", NULL,
/* Translators: The '%s' is replaced with a spin button with the actual value */
N_("Store folder changes after %s second(s)"), "" },
+ { CAMEL_PROVIDER_CONF_CHECKBOX, "single-client-mode", NULL,
+ N_("Single client mode"), "1" },
{ CAMEL_PROVIDER_CONF_SECTION_END },
{ CAMEL_PROVIDER_CONF_END }
};
diff --git a/src/camel/providers/imapx/camel-imapx-server.c b/src/camel/providers/imapx/camel-imapx-server.c
index e43d3ed38..1c4160288 100644
--- a/src/camel/providers/imapx/camel-imapx-server.c
+++ b/src/camel/providers/imapx/camel-imapx-server.c
@@ -5556,13 +5556,36 @@ imapx_server_fetch_changes (CamelIMAPXServer *is,
return success;
}
+/* It does not verify single-client-mode, it only checks whether it's time
+ to do a full update according to folder's last-full-update property and
+ return TRUE, when the full update should be done. It also stores the current
+ time when returning TRUE. */
static gboolean
-camel_imapx_server_skip_old_flags_update (CamelStore *store)
+camel_imapx_server_check_folder_last_full_update (CamelFolder *folder)
{
+ gint64 now = g_get_real_time () / G_USEC_PER_SEC;
+ gint64 diff = now - camel_imapx_folder_get_last_full_update (CAMEL_IMAPX_FOLDER (folder));
+
+ if (diff > 0 && diff < 24 * 60 * 60)
+ return FALSE;
+
+ camel_imapx_folder_set_last_full_update (CAMEL_IMAPX_FOLDER (folder), now);
+ camel_object_state_write (CAMEL_OBJECT (folder));
+
+ return TRUE;
+}
+
+static gboolean
+camel_imapx_server_do_old_flags_update (CamelFolder *folder)
+{
+ CamelStore *store;
CamelSession *session;
CamelSettings *settings;
GNetworkMonitor *network_monitor;
- gboolean skip_old_flags_update = FALSE;
+ gboolean do_old_flags_update = TRUE;
+ gboolean single_client_mode = FALSE;
+
+ store = camel_folder_get_parent_store (folder);
if (!CAMEL_IS_STORE (store))
return FALSE;
@@ -5572,23 +5595,28 @@ camel_imapx_server_skip_old_flags_update (CamelStore *store)
gboolean allow_update;
allow_update = camel_imapx_settings_get_full_update_on_metered_network (CAMEL_IMAPX_SETTINGS (settings));
+ single_client_mode = camel_imapx_settings_get_single_client_mode (CAMEL_IMAPX_SETTINGS (settings));
g_object_unref (settings);
- if (allow_update)
- return FALSE;
+ if (allow_update) {
+ if (single_client_mode)
+ do_old_flags_update = camel_imapx_server_check_folder_last_full_update (folder);
+
+ return do_old_flags_update;
+ }
}
session = camel_service_ref_session (CAMEL_SERVICE (store));
if (!session)
- return skip_old_flags_update;
+ return do_old_flags_update;
network_monitor = camel_session_ref_network_monitor (session);
- skip_old_flags_update = network_monitor && g_network_monitor_get_network_metered (network_monitor);
+ do_old_flags_update = !network_monitor || !g_network_monitor_get_network_metered (network_monitor);
#ifdef HAVE_GPOWERPROFILEMONITOR
- if (!skip_old_flags_update) {
+ if (do_old_flags_update) {
GSettings *eds_settings;
eds_settings = g_settings_new ("org.gnome.evolution-data-server");
@@ -5597,7 +5625,7 @@ camel_imapx_server_skip_old_flags_update (CamelStore *store)
GPowerProfileMonitor *power_monitor;
power_monitor = g_power_profile_monitor_dup_default ();
- skip_old_flags_update = power_monitor && g_power_profile_monitor_get_power_saver_enabled (power_monitor);
+ do_old_flags_update = !power_monitor || !g_power_profile_monitor_get_power_saver_enabled (power_monitor);
g_clear_object (&power_monitor);
}
@@ -5607,7 +5635,10 @@ camel_imapx_server_skip_old_flags_update (CamelStore *store)
g_clear_object (&network_monitor);
g_clear_object (&session);
- return skip_old_flags_update;
+ if (single_client_mode && do_old_flags_update)
+ do_old_flags_update = camel_imapx_server_check_folder_last_full_update (folder);
+
+ return do_old_flags_update;
}
gboolean
@@ -5630,7 +5661,7 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
guint64 highestmodseq;
guint32 total;
guint64 uidl;
- gboolean need_rescan, skip_old_flags_update;
+ gboolean need_rescan, do_old_flags_update;
gboolean success;
g_return_val_if_fail (CAMEL_IS_IMAPX_SERVER (is), FALSE);
@@ -5738,9 +5769,9 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
known_uids = g_hash_table_new_full (g_str_hash, g_str_equal, (GDestroyNotify) camel_pstring_free, NULL);
- skip_old_flags_update = camel_imapx_server_skip_old_flags_update (camel_folder_get_parent_store (folder));
+ do_old_flags_update = camel_imapx_server_do_old_flags_update (folder);
- if (!skip_old_flags_update) {
+ if (do_old_flags_update) {
/* Remember summary state before running the update, in case there are
added new messages into the folder meanwhile, like with a COPY/MOVE filter;
such new messages would be considered removed, because not being part
@@ -5749,7 +5780,7 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
}
success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, uidl, 0, cancellable, error);
- if (success && uidl != 1 && !skip_old_flags_update)
+ if (success && uidl != 1 && do_old_flags_update)
success = imapx_server_fetch_changes (is, mailbox, folder, known_uids, 0, uidl, cancellable, error);
if (success) {
@@ -5766,7 +5797,7 @@ camel_imapx_server_refresh_info_sync (CamelIMAPXServer *is,
g_mutex_unlock (&is->priv->changes_lock);
- if (success && !skip_old_flags_update) {
+ if (success && do_old_flags_update) {
GList *removed = NULL;
gint ii;
diff --git a/src/camel/providers/imapx/camel-imapx-settings.c b/src/camel/providers/imapx/camel-imapx-settings.c
index af1fc93fb..ff386fb89 100644
--- a/src/camel/providers/imapx/camel-imapx-settings.c
+++ b/src/camel/providers/imapx/camel-imapx-settings.c
@@ -48,6 +48,7 @@ struct _CamelIMAPXSettingsPrivate {
gboolean ignore_shared_folders_namespace;
gboolean full_update_on_metered_network;
gboolean send_client_id;
+ gboolean single_client_mode;
CamelSortType fetch_order;
};
@@ -81,7 +82,8 @@ enum {
PROP_IGNORE_OTHER_USERS_NAMESPACE,
PROP_IGNORE_SHARED_FOLDERS_NAMESPACE,
PROP_FULL_UPDATE_ON_METERED_NETWORK,
- PROP_SEND_CLIENT_ID
+ PROP_SEND_CLIENT_ID,
+ PROP_SINGLE_CLIENT_MODE
};
G_DEFINE_TYPE_WITH_CODE (
@@ -266,6 +268,12 @@ imapx_settings_set_property (GObject *object,
CAMEL_IMAPX_SETTINGS (object),
g_value_get_boolean (value));
return;
+
+ case PROP_SINGLE_CLIENT_MODE:
+ camel_imapx_settings_set_single_client_mode (
+ CAMEL_IMAPX_SETTINGS (object),
+ g_value_get_boolean (value));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -473,6 +481,13 @@ imapx_settings_get_property (GObject *object,
camel_imapx_settings_get_send_client_id (
CAMEL_IMAPX_SETTINGS (object)));
return;
+
+ case PROP_SINGLE_CLIENT_MODE:
+ g_value_set_boolean (
+ value,
+ camel_imapx_settings_get_single_client_mode (
+ CAMEL_IMAPX_SETTINGS (object)));
+ return;
}
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -838,6 +853,19 @@ camel_imapx_settings_class_init (CamelIMAPXSettingsClass *class)
G_PARAM_CONSTRUCT |
G_PARAM_EXPLICIT_NOTIFY |
G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
+ PROP_SINGLE_CLIENT_MODE,
+ g_param_spec_boolean (
+ "single-client-mode",
+ "Single Client Mode",
+ "When set to true, does full folder flags refresh only once per day",
+ TRUE,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_EXPLICIT_NOTIFY |
+ G_PARAM_STATIC_STRINGS));
}
static void
@@ -2022,3 +2050,46 @@ camel_imapx_settings_set_send_client_id (CamelIMAPXSettings *settings,
g_object_notify (G_OBJECT (settings), "send-client-id");
}
+
+/**
+ * camel_imapx_settings_get_single_client_mode:
+ * @settings: a #CamelIMAPXSettings
+ *
+ * Returns whether using single client mode. That is, the full folder refresh
+ * flags are done only once per day, not on each folder refresh.
+ *
+ * Returns: whether the single client mode is enabled
+ *
+ * Since: 3.50
+ **/
+gboolean
+camel_imapx_settings_get_single_client_mode (CamelIMAPXSettings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings), FALSE);
+
+ return settings->priv->single_client_mode;
+}
+
+/**
+ * camel_imapx_settings_set_single_client_mode:
+ * @settings: a #CamelIMAPXSettings
+ * @single_client_mode: value to set
+ *
+ * Sets whether to use a single client mode. See camel_imapx_settings_get_single_client_mode()
+ * for an explanation what it means.
+ *
+ * Since: 3.50
+ **/
+void
+camel_imapx_settings_set_single_client_mode (CamelIMAPXSettings *settings,
+ gboolean single_client_mode)
+{
+ g_return_if_fail (CAMEL_IS_IMAPX_SETTINGS (settings));
+
+ if ((settings->priv->single_client_mode ? 1 : 0) == (single_client_mode ? 1 : 0))
+ return;
+
+ settings->priv->single_client_mode = single_client_mode;
+
+ g_object_notify (G_OBJECT (settings), "single-client-mode");
+}
diff --git a/src/camel/providers/imapx/camel-imapx-settings.h b/src/camel/providers/imapx/camel-imapx-settings.h
index a23a75a02..37e618b52 100644
--- a/src/camel/providers/imapx/camel-imapx-settings.h
+++ b/src/camel/providers/imapx/camel-imapx-settings.h
@@ -181,6 +181,11 @@ gboolean camel_imapx_settings_get_send_client_id
void camel_imapx_settings_set_send_client_id
(CamelIMAPXSettings *settings,
gboolean send_client_id);
+gboolean camel_imapx_settings_get_single_client_mode
+ (CamelIMAPXSettings *settings);
+void camel_imapx_settings_set_single_client_mode
+ (CamelIMAPXSettings *settings,
+ gboolean single_client_mode);
G_END_DECLS