[evolution-data-server] Bug 343904 - [POP3] Local cache keeps stored orphaned files
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Bug 343904 - [POP3] Local cache keeps stored orphaned files
- Date: Wed, 21 Jun 2017 08:34:19 +0000 (UTC)
commit af6938510c2744928d0613095706247bae3204a9
Author: Milan Crha <mcrha redhat com>
Date: Wed Jun 21 10:30:19 2017 +0200
Bug 343904 - [POP3] Local cache keeps stored orphaned files
src/camel/camel-data-cache.c | 91 ++++++++++++++++++++++++
src/camel/camel-data-cache.h | 22 ++++++
src/camel/providers/pop3/camel-pop3-folder.c | 89 +++++++++++++++++++++++-
src/camel/providers/pop3/camel-pop3-settings.c | 52 +++++++++++++-
src/camel/providers/pop3/camel-pop3-settings.h | 5 ++
5 files changed, 257 insertions(+), 2 deletions(-)
---
diff --git a/src/camel/camel-data-cache.c b/src/camel/camel-data-cache.c
index 818ed60..3be6943 100644
--- a/src/camel/camel-data-cache.c
+++ b/src/camel/camel-data-cache.c
@@ -665,3 +665,94 @@ camel_data_cache_clear (CamelDataCache *cdc,
g_dir_close (dir);
g_free (base_dir);
}
+
+static void
+data_cache_foreach_remove (CamelDataCache *cdc,
+ const gchar *path,
+ CamelDataCacheRemoveFunc func,
+ gpointer user_data)
+{
+ GDir *dir;
+ const gchar *dname;
+ struct stat st;
+ GIOStream *stream;
+
+ dir = g_dir_open (path, 0, NULL);
+ if (!dir)
+ return;
+
+ while ((dname = g_dir_read_name (dir))) {
+ gchar *filename;
+
+ filename = g_build_filename (path, dname, NULL);
+
+ if (g_stat (filename, &st) == 0
+ && S_ISREG (st.st_mode)
+ && func (cdc, filename, user_data)) {
+ g_unlink (filename);
+ stream = camel_object_bag_get (cdc->priv->busy_bag, filename);
+ if (stream) {
+ camel_object_bag_remove (cdc->priv->busy_bag, stream);
+ g_object_unref (stream);
+ }
+ }
+
+ g_free (filename);
+ }
+
+ g_dir_close (dir);
+}
+
+/**
+ * camel_data_cache_foreach_remove:
+ * @cdc: a #CamelDataCache
+ * @path: Path to the (sub) cache the items exist in
+ * @func: (scope call) (closure user_data): a callback to call for each found file in the cache
+ * @user_data: user data passed to @func
+ *
+ * Traverses the @cdc sub-cache identified by @path and calls @func for each found file.
+ * If the @func returns %TRUE, then the file is removed, if %FALSE, it's kept in the cache.
+ *
+ * Since: 3.26
+ **/
+void
+camel_data_cache_foreach_remove (CamelDataCache *cdc,
+ const gchar *path,
+ CamelDataCacheRemoveFunc func,
+ gpointer user_data)
+{
+ gchar *base_dir;
+ GDir *dir;
+ const gchar *dname;
+ struct stat st;
+
+ g_return_if_fail (CAMEL_IS_DATA_CACHE (cdc));
+ g_return_if_fail (path != NULL);
+ g_return_if_fail (func != NULL);
+
+ base_dir = g_build_filename (cdc->priv->path, path, NULL);
+
+ dir = g_dir_open (base_dir, 0, NULL);
+ if (dir == NULL) {
+ g_free (base_dir);
+ return;
+ }
+
+ while ((dname = g_dir_read_name (dir))) {
+ gchar *dpath;
+
+ dpath = g_build_filename (base_dir, dname, NULL);
+
+ if (g_stat (dpath, &st) == 0
+ && S_ISDIR (st.st_mode)
+ && !g_str_equal (dname, ".")
+ && !g_str_equal (dname, "..")) {
+ data_cache_foreach_remove (cdc, dpath, func, user_data);
+ }
+
+ g_free (dpath);
+ }
+
+ g_dir_close (dir);
+ g_free (base_dir);
+}
diff --git a/src/camel/camel-data-cache.h b/src/camel/camel-data-cache.h
index e5725f2..2654baf 100644
--- a/src/camel/camel-data-cache.h
+++ b/src/camel/camel-data-cache.h
@@ -52,6 +52,24 @@ typedef struct _CamelDataCache CamelDataCache;
typedef struct _CamelDataCacheClass CamelDataCacheClass;
typedef struct _CamelDataCachePrivate CamelDataCachePrivate;
+/**
+ * CamelDataCacheRemoveFunc:
+ * @cdc: a #CamelDataCache
+ * @filename: a file name found in the cache
+ * @user_data: user data passed to camel_data_cache_foreach_remove()
+ *
+ * A callback called for each found file in the cache, used
+ * by camel_data_cache_foreach_remove(). The @filename corresponds
+ * to the result of camel_data_cache_get_filename().
+ *
+ * Returns: %TRUE, to delete the file, %FALSE to keep in in the cache
+ *
+ * Since: 3.26
+ **/
+typedef gboolean (* CamelDataCacheRemoveFunc) (CamelDataCache *cdc,
+ const gchar *filename,
+ gpointer user_data);
+
struct _CamelDataCache {
GObject parent;
CamelDataCachePrivate *priv;
@@ -97,6 +115,10 @@ gchar * camel_data_cache_get_filename (CamelDataCache *cdc,
const gchar *key);
void camel_data_cache_clear (CamelDataCache *cdc,
const gchar *path);
+void camel_data_cache_foreach_remove (CamelDataCache *cdc,
+ const gchar *path,
+ CamelDataCacheRemoveFunc func,
+ gpointer user_data);
G_END_DECLS
diff --git a/src/camel/providers/pop3/camel-pop3-folder.c b/src/camel/providers/pop3/camel-pop3-folder.c
index 1db295b..9998625 100644
--- a/src/camel/providers/pop3/camel-pop3-folder.c
+++ b/src/camel/providers/pop3/camel-pop3-folder.c
@@ -768,6 +768,89 @@ pop3_folder_refresh_info_sync (CamelFolder *folder,
return success;
}
+static guint32
+pop3_folder_get_current_time_mark (void)
+{
+ GDate date;
+
+ g_date_clear (&date, 1);
+ g_date_set_time_t (&date, time (NULL));
+
+ return g_date_get_julian (&date);
+}
+
+static gboolean
+pop3_folder_cache_foreach_remove_cb (CamelDataCache *cache,
+ const gchar *filename,
+ gpointer user_data)
+{
+ GHashTable *filenames = user_data;
+
+ g_return_val_if_fail (filenames != NULL, FALSE);
+
+ return !g_hash_table_contains (filenames, filename);
+}
+
+static void
+pop3_folder_maybe_expunge_cache (CamelPOP3Folder *pop3_folder)
+{
+ CamelService *service;
+ CamelSettings *settings;
+ CamelDataCache *pop3_cache;
+ GHashTable *filenames;
+ guint32 last_cache_expunge, current_time;
+ gint ii;
+
+ g_return_if_fail (CAMEL_IS_POP3_FOLDER (pop3_folder));
+
+ service = CAMEL_SERVICE (camel_folder_get_parent_store (CAMEL_FOLDER (pop3_folder)));
+ g_return_if_fail (CAMEL_IS_SERVICE (service));
+
+ /* Expunge local cache only if online, which should guarantee that
+ the 'pop3_folder->uids' is properly populated. */
+ if (camel_service_get_connection_status (service) != CAMEL_SERVICE_CONNECTED)
+ return;
+
+ pop3_cache = camel_pop3_store_ref_cache (CAMEL_POP3_STORE (service));
+ g_return_if_fail (CAMEL_IS_DATA_CACHE (pop3_cache));
+
+ settings = camel_service_ref_settings (service);
+
+ last_cache_expunge = camel_pop3_settings_get_last_cache_expunge (CAMEL_POP3_SETTINGS (settings));
+ current_time = pop3_folder_get_current_time_mark ();
+
+ if (last_cache_expunge + 7 > current_time && current_time >= last_cache_expunge) {
+ d (printf ("%s: No need to expunge cache yet; last did %d, now is %d\n", G_STRFUNC,
last_cache_expunge, current_time));
+ g_clear_object (&pop3_cache);
+ g_clear_object (&settings);
+ return;
+ }
+
+ d (printf ("%s: Going to expunge cache; last did %d, now is %d\n", G_STRFUNC, last_cache_expunge,
current_time));
+ camel_pop3_settings_set_last_cache_expunge (CAMEL_POP3_SETTINGS (settings), current_time);
+ g_clear_object (&settings);
+
+ filenames = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ for (ii = 0; ii < pop3_folder->uids->len; ii++) {
+ CamelPOP3FolderInfo *fi = pop3_folder->uids->pdata[ii];
+ gchar *filename;
+
+ if (!fi || !fi->uid)
+ continue;
+
+ filename = camel_data_cache_get_filename (pop3_cache, "cache", fi->uid);
+ if (filename)
+ g_hash_table_insert (filenames, filename, NULL);
+ }
+
+ d (printf ("%s: Recognized %d downloaded messages\n", G_STRFUNC, g_hash_table_size (filenames)));
+ camel_data_cache_foreach_remove (pop3_cache, "cache", pop3_folder_cache_foreach_remove_cb, filenames);
+
+ g_hash_table_destroy (filenames);
+ g_clear_object (&pop3_cache);
+}
+
static gboolean
pop3_folder_synchronize_sync (CamelFolder *folder,
gboolean expunge,
@@ -825,8 +908,10 @@ pop3_folder_synchronize_sync (CamelFolder *folder,
return FALSE;
}
- if (!expunge || (keep_on_server && !delete_expunged))
+ if (!expunge || (keep_on_server && !delete_expunged)) {
+ pop3_folder_maybe_expunge_cache (pop3_folder);
return TRUE;
+ }
if (!is_online) {
g_set_error (
@@ -911,6 +996,8 @@ pop3_folder_synchronize_sync (CamelFolder *folder,
g_clear_object (&pop3_cache);
g_clear_object (&pop3_engine);
+ pop3_folder_maybe_expunge_cache (pop3_folder);
+
camel_operation_pop_message (cancellable);
return camel_pop3_store_expunge (pop3_store, cancellable, error);
diff --git a/src/camel/providers/pop3/camel-pop3-settings.c b/src/camel/providers/pop3/camel-pop3-settings.c
index e4e048f..f315e09 100644
--- a/src/camel/providers/pop3/camel-pop3-settings.c
+++ b/src/camel/providers/pop3/camel-pop3-settings.c
@@ -27,6 +27,7 @@ struct _CamelPOP3SettingsPrivate {
gboolean disable_extensions;
gboolean keep_on_server;
gboolean auto_fetch;
+ guint32 last_cache_expunge;
};
enum {
@@ -40,7 +41,8 @@ enum {
PROP_PORT,
PROP_SECURITY_METHOD,
PROP_USER,
- PROP_AUTO_FETCH
+ PROP_AUTO_FETCH,
+ PROP_LAST_CACHE_EXPUNGE
};
G_DEFINE_TYPE_WITH_CODE (
@@ -93,6 +95,12 @@ pop3_settings_set_property (GObject *object,
g_value_get_boolean (value));
return;
+ case PROP_LAST_CACHE_EXPUNGE:
+ camel_pop3_settings_set_last_cache_expunge (
+ CAMEL_POP3_SETTINGS (object),
+ g_value_get_uint (value));
+ return;
+
case PROP_PORT:
camel_network_settings_set_port (
CAMEL_NETWORK_SETTINGS (object),
@@ -170,6 +178,13 @@ pop3_settings_get_property (GObject *object,
CAMEL_POP3_SETTINGS (object)));
return;
+ case PROP_LAST_CACHE_EXPUNGE:
+ g_value_set_uint (
+ value,
+ camel_pop3_settings_get_last_cache_expunge (
+ CAMEL_POP3_SETTINGS (object)));
+ return;
+
case PROP_PORT:
g_value_set_uint (
value,
@@ -279,6 +294,20 @@ camel_pop3_settings_class_init (CamelPOP3SettingsClass *class)
g_object_class_install_property (
object_class,
+ PROP_LAST_CACHE_EXPUNGE,
+ g_param_spec_uint (
+ "last-cache-expunge",
+ "Last Cache Expunge",
+ "Date as Julian value, when the cache had been checked for orphaned files the last
time",
+ 0,
+ G_MAXUINT32,
+ 0,
+ G_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property (
+ object_class,
PROP_AUTO_FETCH,
g_param_spec_boolean (
"auto-fetch",
@@ -541,3 +570,24 @@ camel_pop3_settings_set_auto_fetch (CamelPOP3Settings *settings,
g_object_notify (G_OBJECT (settings), "auto-fetch");
}
+guint32
+camel_pop3_settings_get_last_cache_expunge (CamelPOP3Settings *settings)
+{
+ g_return_val_if_fail (CAMEL_IS_POP3_SETTINGS (settings), 0);
+
+ return settings->priv->last_cache_expunge;
+}
+
+void
+camel_pop3_settings_set_last_cache_expunge (CamelPOP3Settings *settings,
+ guint32 last_cache_expunge)
+{
+ g_return_if_fail (CAMEL_IS_POP3_SETTINGS (settings));
+
+ if (settings->priv->last_cache_expunge == last_cache_expunge)
+ return;
+
+ settings->priv->last_cache_expunge = last_cache_expunge;
+
+ g_object_notify (G_OBJECT (settings), "last-cache-expunge");
+}
diff --git a/src/camel/providers/pop3/camel-pop3-settings.h b/src/camel/providers/pop3/camel-pop3-settings.h
index d69b71b..fe30dca 100644
--- a/src/camel/providers/pop3/camel-pop3-settings.h
+++ b/src/camel/providers/pop3/camel-pop3-settings.h
@@ -83,6 +83,11 @@ gboolean camel_pop3_settings_get_auto_fetch
void camel_pop3_settings_set_auto_fetch
(CamelPOP3Settings *settings,
gboolean auto_fetch);
+guint32 camel_pop3_settings_get_last_cache_expunge
+ (CamelPOP3Settings *settings);
+void camel_pop3_settings_set_last_cache_expunge
+ (CamelPOP3Settings *settings,
+ guint32 last_cache_expunge);
G_END_DECLS
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]