[evolution-data-server] Simplify vFolder's code and other bunch of related time optimizations
- From: Milan Crha <mcrha src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [evolution-data-server] Simplify vFolder's code and other bunch of related time optimizations
- Date: Wed, 30 May 2012 16:46:25 +0000 (UTC)
commit 76d8bbcdc47c6cf2c343d21a694110026ecab98d
Author: Milan Crha <mcrha redhat com>
Date: Wed May 30 18:45:01 2012 +0200
Simplify vFolder's code and other bunch of related time optimizations
camel/Makefile.am | 2 +
camel/camel-db.c | 209 ---
camel/camel-db.h | 9 -
camel/camel-folder-search.c | 70 +-
camel/camel-folder-summary.c | 279 +++-
camel/camel-folder-summary.h | 17 +-
camel/camel-folder.c | 4 +
camel/camel-imapx-server.c | 2 +-
camel/camel-store.c | 13 +-
camel/camel-string-utils.c | 79 +-
camel/camel-string-utils.h | 1 +
camel/camel-subscribable.c | 4 +-
camel/camel-vee-data-cache.c | 638 ++++++++
camel/camel-vee-data-cache.h | 177 ++
camel/camel-vee-folder.c | 2597 ++++++++++--------------------
camel/camel-vee-folder.h | 92 +-
camel/camel-vee-store.c | 532 ++++++-
camel/camel-vee-store.h | 40 +-
camel/camel-vee-summary.c | 293 +++-
camel/camel-vee-summary.h | 18 +-
camel/camel-vtrash-folder.c | 4 +-
camel/camel.h | 1 +
camel/providers/imap/camel-imap-folder.c | 2 +-
23 files changed, 2824 insertions(+), 2259 deletions(-)
---
diff --git a/camel/Makefile.am b/camel/Makefile.am
index e9ceed4..d1652dc 100644
--- a/camel/Makefile.am
+++ b/camel/Makefile.am
@@ -168,6 +168,7 @@ libcamel_1_2_la_SOURCES = \
camel-url-scanner.c \
camel-url.c \
camel-utf8.c \
+ camel-vee-data-cache.c \
camel-vee-folder.c \
camel-vee-store.c \
camel-vee-summary.c \
@@ -302,6 +303,7 @@ libcamelinclude_HEADERS = \
camel-url-scanner.h \
camel-url.h \
camel-utf8.h \
+ camel-vee-data-cache.h \
camel-vee-folder.h \
camel-vee-store.h \
camel-vee-summary.h \
diff --git a/camel/camel-db.c b/camel/camel-db.c
index 8fb123e..c8ef256 100644
--- a/camel/camel-db.c
+++ b/camel/camel-db.c
@@ -994,103 +994,6 @@ camel_db_select (CamelDB *cdb,
return ret;
}
-/**
- * camel_db_create_vfolder:
- *
- * Since: 2.24
- **/
-gint
-camel_db_create_vfolder (CamelDB *db,
- const gchar *folder_name,
- GError **error)
-{
- gint ret;
- gchar *table_creation_query, *safe_index;
-
- table_creation_query = sqlite3_mprintf ("CREATE TABLE IF NOT EXISTS %Q ( vuid TEXT PRIMARY KEY)", folder_name);
-
- ret = camel_db_command (db, table_creation_query, error);
-
- sqlite3_free (table_creation_query);
-
- safe_index = g_strdup_printf("VINDEX-%s", folder_name);
- table_creation_query = sqlite3_mprintf ("CREATE INDEX IF NOT EXISTS %Q ON %Q (vuid)", safe_index, folder_name);
- ret = camel_db_command (db, table_creation_query, error);
-
- sqlite3_free (table_creation_query);
- g_free (safe_index);
- CAMEL_DB_RELEASE_SQLITE_MEMORY;
-
- return ret;
-}
-
-/**
- * camel_db_recreate_vfolder:
- *
- * Since: 2.24
- **/
-gint
-camel_db_recreate_vfolder (CamelDB *db,
- const gchar *folder_name,
- GError **error)
-{
- gchar *table_query;
-
- table_query = sqlite3_mprintf ("DROP TABLE %Q", folder_name);
-
- camel_db_command (db, table_query, error);
-
- sqlite3_free (table_query);
-
- return camel_db_create_vfolder (db, folder_name, error);
-}
-
-/**
- * camel_db_delete_uid_from_vfolder:
- *
- * Since: 2.24
- **/
-gint
-camel_db_delete_uid_from_vfolder (CamelDB *db,
- gchar *folder_name,
- gchar *vuid,
- GError **error)
-{
- gchar *del_query;
- gint ret;
-
- del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE vuid = %Q", folder_name, vuid);
-
- ret = camel_db_command (db, del_query, error);
-
- sqlite3_free (del_query);
- CAMEL_DB_RELEASE_SQLITE_MEMORY;
- return ret;
-}
-
-/**
- * camel_db_delete_uid_from_vfolder_transaction:
- *
- * Since: 2.24
- **/
-gint
-camel_db_delete_uid_from_vfolder_transaction (CamelDB *db,
- const gchar *folder_name,
- const gchar *vuid,
- GError **error)
-{
- gchar *del_query;
- gint ret;
-
- del_query = sqlite3_mprintf ("DELETE FROM %Q WHERE vuid = %Q", folder_name, vuid);
-
- ret = camel_db_add_to_transaction (db, del_query, error);
-
- sqlite3_free (del_query);
-
- return ret;
-}
-
static gint
read_uids_callback (gpointer ref_array,
gint ncol,
@@ -1299,103 +1202,6 @@ camel_db_write_preview_record (CamelDB *db,
return ret;
}
-static gint
-read_vuids_callback (gpointer ref,
- gint ncol,
- gchar **cols,
- gchar **name)
-{
- GPtrArray *array = (GPtrArray *) ref;
-
- if (cols[0] && strlen (cols[0]) > 8)
- g_ptr_array_add (array, (gchar *) (camel_pstring_strdup (cols[0]+8)));
-
- return 0;
-}
-
-/**
- * camel_db_get_vuids_from_vfolder:
- *
- * Since: 2.24
- **/
-GPtrArray *
-camel_db_get_vuids_from_vfolder (CamelDB *db,
- const gchar *folder_name,
- gchar *filter,
- GError **error)
-{
- gchar *sel_query;
- gchar *cond = NULL;
- GPtrArray *array;
- gchar *tmp = g_strdup_printf("%s%%", filter ? filter:"");
- if (filter)
- cond = sqlite3_mprintf(" WHERE vuid LIKE %Q", tmp);
- g_free (tmp);
- sel_query = sqlite3_mprintf("SELECT vuid FROM %Q%s", folder_name, filter ? cond : "");
-
- if (cond)
- sqlite3_free (cond);
- /* FIXME[disk-summary] handle return values */
- /* FIXME[disk-summary] No The caller should parse the ex in case
- * of NULL returns */
- array = g_ptr_array_new ();
- camel_db_select (db, sel_query, read_vuids_callback, array, error);
- sqlite3_free (sel_query);
- /* We make sure to return NULL if we don't get anything. Be good to your caller */
- if (!array->len) {
- g_ptr_array_free (array, TRUE);
- array = NULL;
- }
-
- return array;
-}
-
-/**
- * camel_db_add_to_vfolder:
- *
- * Since: 2.24
- **/
-gint
-camel_db_add_to_vfolder (CamelDB *db,
- gchar *folder_name,
- gchar *vuid,
- GError **error)
-{
- gchar *ins_query;
- gint ret;
-
- ins_query = sqlite3_mprintf ("INSERT INTO %Q VALUES (%Q)", folder_name, vuid);
-
- ret = camel_db_command (db, ins_query, error);
-
- sqlite3_free (ins_query);
- CAMEL_DB_RELEASE_SQLITE_MEMORY;
- return ret;
-}
-
-/**
- * camel_db_add_to_vfolder_transaction:
- *
- * Since: 2.24
- **/
-gint
-camel_db_add_to_vfolder_transaction (CamelDB *db,
- const gchar *folder_name,
- const gchar *vuid,
- GError **error)
-{
- gchar *ins_query;
- gint ret;
-
- ins_query = sqlite3_mprintf ("INSERT INTO %Q VALUES (%Q)", folder_name, vuid);
-
- ret = camel_db_add_to_transaction (db, ins_query, error);
-
- sqlite3_free (ins_query);
-
- return ret;
-}
-
/**
* camel_db_create_folders_table:
*
@@ -2123,21 +1929,6 @@ camel_db_delete_uids (CamelDB *cdb,
}
/**
- * camel_db_delete_vuids:
- *
- * Since: 2.26
- **/
-gint
-camel_db_delete_vuids (CamelDB *cdb,
- const gchar *folder_name,
- const gchar *hash,
- GList *uids,
- GError **error)
-{
- return cdb_delete_ids (cdb, folder_name, uids, hash, "vuid", error);
-}
-
-/**
* camel_db_clear_folder_summary:
*
* Since: 2.24
diff --git a/camel/camel-db.h b/camel/camel-db.h
index 33be066..deb9a11 100644
--- a/camel/camel-db.h
+++ b/camel/camel-db.h
@@ -273,7 +273,6 @@ gint camel_db_delete_folder (CamelDB *cdb, const gchar *folder, GError **error);
gint camel_db_delete_uid (CamelDB *cdb, const gchar *folder, const gchar *uid, GError **error);
/*int camel_db_delete_uids (CamelDB *cdb, GError **error, gint nargs, ... );*/
gint camel_db_delete_uids (CamelDB *cdb, const gchar * folder_name, GList *uids, GError **error);
-gint camel_db_delete_vuids (CamelDB *cdb, const gchar * folder_name, const gchar *shash, GList *uids, GError **error);
gint camel_db_create_folders_table (CamelDB *cdb, GError **error);
gint camel_db_select (CamelDB *cdb, const gchar * stmt, CamelDBSelectCB callback, gpointer data, GError **error);
@@ -300,14 +299,6 @@ gint camel_db_count_junk_not_deleted_message_info (CamelDB *cdb, const gchar *ta
gint camel_db_count_message_info (CamelDB *cdb, const gchar *query, guint32 *count, GError **error);
void camel_db_camel_mir_free (CamelMIRecord *record);
-gint camel_db_create_vfolder (CamelDB *db, const gchar *folder_name, GError **error);
-gint camel_db_recreate_vfolder (CamelDB *db, const gchar *folder_name, GError **error);
-gint camel_db_delete_uid_from_vfolder (CamelDB *db, gchar *folder_name, gchar *vuid, GError **error);
-gint camel_db_delete_uid_from_vfolder_transaction (CamelDB *db, const gchar *folder_name, const gchar *vuid, GError **error);
-GPtrArray * camel_db_get_vuids_from_vfolder (CamelDB *db, const gchar *folder_name, gchar *filter, GError **error);
-gint camel_db_add_to_vfolder (CamelDB *db, gchar *folder_name, gchar *vuid, GError **error);
-gint camel_db_add_to_vfolder_transaction (CamelDB *db, const gchar *folder_name, const gchar *vuid, GError **error);
-
gint camel_db_get_folder_uids (CamelDB *db, const gchar *folder_name, const gchar *sort_by, const gchar *collate, GHashTable *hash, GError **error);
GPtrArray * camel_db_get_folder_junk_uids (CamelDB *db, gchar *folder_name, GError **error);
diff --git a/camel/camel-folder-search.c b/camel/camel-folder-search.c
index c72acc8..ab96996 100644
--- a/camel/camel-folder-search.c
+++ b/camel/camel-folder-search.c
@@ -322,6 +322,40 @@ camel_folder_search_set_body_index (CamelFolderSearch *search,
search->body_index = body_index;
}
+static gboolean
+do_search_in_memory (CamelFolder *search_in_folder,
+ const gchar *expr)
+{
+ /* if the expression contains any of these tokens, then perform a memory search, instead of the SQL one */
+ const gchar *in_memory_tokens[] = {
+ "body-contains",
+ "body-regex",
+ "match-threads",
+ "message-location",
+ "header-soundex",
+ "header-regex",
+ "header-full-regex",
+ "header-contains",
+ "header-has-words",
+ NULL };
+ gint i;
+
+ if (search_in_folder &&
+ search_in_folder->summary &&
+ (search_in_folder->summary->flags & CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY) != 0)
+ return TRUE;
+
+ if (!expr)
+ return FALSE;
+
+ for (i = 0; in_memory_tokens[i]; i++) {
+ if (strstr (expr, in_memory_tokens[i]))
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
/**
* camel_folder_search_count:
* @search:
@@ -363,9 +397,11 @@ camel_folder_search_count (CamelFolderSearch *search,
p->error = error;
/* We route body-contains search and thread based search through memory and not via db. */
- if (strstr((const gchar *) expr, "body-contains") || strstr((const gchar *) expr, "match-threads")) {
+ if (do_search_in_memory (search->folder, expr)) {
/* setup our search list only contains those we're interested in */
search->summary = camel_folder_get_summary (search->folder);
+ if (search->folder->summary)
+ camel_folder_summary_prepare_fetch_all (search->folder->summary, NULL);
summary_set = search->summary;
@@ -474,34 +510,6 @@ fail:
return count;
}
-static gboolean
-do_search_in_memory (const gchar *expr)
-{
- /* if the expression contains any of these tokens, then perform a memory search, instead of the SQL one */
- const gchar *in_memory_tokens[] = {
- "body-contains",
- "body-regex",
- "match-threads",
- "message-location",
- "header-soundex",
- "header-regex",
- "header-full-regex",
- "header-contains",
- "header-has-words",
- NULL };
- gint i;
-
- if (!expr)
- return FALSE;
-
- for (i = 0; in_memory_tokens[i]; i++) {
- if (strstr (expr, in_memory_tokens[i]))
- return TRUE;
- }
-
- return FALSE;
-}
-
/**
* camel_folder_search_search:
* @search:
@@ -541,7 +549,7 @@ camel_folder_search_search (CamelFolderSearch *search,
p->error = error;
/* We route body-contains / thread based search and uid search through memory and not via db. */
- if (uids || do_search_in_memory (expr)) {
+ if (uids || do_search_in_memory (search->folder, expr)) {
/* setup our search list only contains those we're interested in */
search->summary = camel_folder_get_summary (search->folder);
@@ -556,6 +564,8 @@ camel_folder_search_search (CamelFolderSearch *search,
g_ptr_array_add (search->summary_set, search->summary->pdata[i]);
g_hash_table_destroy (uids_hash);
} else {
+ if (search->folder->summary)
+ camel_folder_summary_prepare_fetch_all (search->folder->summary, NULL);
summary_set = search->summary;
}
diff --git a/camel/camel-folder-summary.c b/camel/camel-folder-summary.c
index 8dad22c..a80ca37 100644
--- a/camel/camel-folder-summary.c
+++ b/camel/camel-folder-summary.c
@@ -359,21 +359,32 @@ folder_summary_get_property (GObject *object,
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
-/**
- * folder_summary_update_counts_by_flags:
- *
- * Since: 3.0
- **/
-static void
+static gboolean
+is_in_memory_summary (CamelFolderSummary *summary)
+{
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
+
+ return (summary->flags & CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY) != 0;
+}
+
+#define UPDATE_COUNTS_ADD (1)
+#define UPDATE_COUNTS_SUB (2)
+#define UPDATE_COUNTS_ADD_WITHOUT_TOTAL (3)
+#define UPDATE_COUNTS_SUB_WITHOUT_TOTAL (4)
+
+static gboolean
folder_summary_update_counts_by_flags (CamelFolderSummary *summary,
guint32 flags,
- gboolean subtract)
+ gint op_type)
{
gint unread = 0, deleted = 0, junk = 0;
gboolean is_junk_folder = FALSE, is_trash_folder = FALSE;
+ gboolean subtract = op_type == UPDATE_COUNTS_SUB || op_type == UPDATE_COUNTS_SUB_WITHOUT_TOTAL;
+ gboolean without_total = op_type == UPDATE_COUNTS_ADD_WITHOUT_TOTAL || op_type == UPDATE_COUNTS_SUB_WITHOUT_TOTAL;
+ gboolean changed = FALSE;
GObject *summary_object;
- g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
summary_object = G_OBJECT (summary);
@@ -400,21 +411,25 @@ folder_summary_update_counts_by_flags (CamelFolderSummary *summary,
if (deleted) {
summary->priv->deleted_count += deleted;
g_object_notify (summary_object, "deleted-count");
+ changed = TRUE;
}
if (junk) {
summary->priv->junk_count += junk;
g_object_notify (summary_object, "junk-count");
+ changed = TRUE;
}
if (junk && !deleted) {
summary->priv->junk_not_deleted_count += junk;
g_object_notify (summary_object, "junk-not-deleted-count");
+ changed = TRUE;
}
if (!junk && !deleted) {
summary->priv->visible_count += subtract ? -1 : 1;
g_object_notify (summary_object, "visible-count");
+ changed = TRUE;
}
if (junk && !is_junk_folder)
@@ -425,16 +440,23 @@ folder_summary_update_counts_by_flags (CamelFolderSummary *summary,
if (unread) {
summary->priv->unread_count += unread;
g_object_notify (summary_object, "unread-count");
+ changed = TRUE;
}
- summary->priv->saved_count += subtract ? -1 : 1;
- g_object_notify (summary_object, "saved-count");
+ if (!without_total) {
+ summary->priv->saved_count += subtract ? -1 : 1;
+ g_object_notify (summary_object, "saved-count");
+ changed = TRUE;
+ }
- camel_folder_summary_touch (summary);
+ if (changed)
+ camel_folder_summary_touch (summary);
g_object_thaw_notify (summary_object);
dd(printf("%p: %d %d %d | %d %d %d\n", (gpointer) summary, unread, deleted, junk, summary->priv->unread_count, summary->priv->visible_count, summary->priv->saved_count));
+
+ return changed;
}
static gboolean
@@ -499,19 +521,21 @@ summary_header_to_db (CamelFolderSummary *summary,
record->nextuid = summary->priv->nextuid;
record->time = summary->time;
- /* FIXME: Ever heard of Constructors and initializing ? */
- if (camel_db_count_total_message_info (db, table_name, &(record->saved_count), NULL))
- record->saved_count = 0;
- if (camel_db_count_junk_message_info (db, table_name, &(record->junk_count), NULL))
- record->junk_count = 0;
- if (camel_db_count_deleted_message_info (db, table_name, &(record->deleted_count), NULL))
- record->deleted_count = 0;
- if (camel_db_count_unread_message_info (db, table_name, &(record->unread_count), NULL))
- record->unread_count = 0;
- if (camel_db_count_visible_message_info (db, table_name, &(record->visible_count), NULL))
- record->visible_count = 0;
- if (camel_db_count_junk_not_deleted_message_info (db, table_name, &(record->jnd_count), NULL))
- record->jnd_count = 0;
+ if (!is_in_memory_summary (summary)) {
+ /* FIXME: Ever heard of Constructors and initializing ? */
+ if (camel_db_count_total_message_info (db, table_name, &(record->saved_count), NULL))
+ record->saved_count = 0;
+ if (camel_db_count_junk_message_info (db, table_name, &(record->junk_count), NULL))
+ record->junk_count = 0;
+ if (camel_db_count_deleted_message_info (db, table_name, &(record->deleted_count), NULL))
+ record->deleted_count = 0;
+ if (camel_db_count_unread_message_info (db, table_name, &(record->unread_count), NULL))
+ record->unread_count = 0;
+ if (camel_db_count_visible_message_info (db, table_name, &(record->visible_count), NULL))
+ record->visible_count = 0;
+ if (camel_db_count_junk_not_deleted_message_info (db, table_name, &(record->jnd_count), NULL))
+ record->jnd_count = 0;
+ }
summary->priv->unread_count = record->unread_count;
summary->priv->deleted_count = record->deleted_count;
@@ -798,14 +822,24 @@ content_info_to_db (CamelFolderSummary *summary,
return TRUE;
}
-static gboolean
-folder_summary_replace_flags (CamelFolderSummary *summary,
- CamelMessageInfo *info)
+/**
+ * camel_folder_summary_replace_flags:
+ * @summary: a #CamelFolderSummary
+ * @info: a #CamelMessageInfo
+ *
+ * Updates internal counts based on the flags in @info.
+ *
+ * Returns: Whether any count changed
+ *
+ * Since: 3.6
+ **/
+gboolean
+camel_folder_summary_replace_flags (CamelFolderSummary *summary,
+ CamelMessageInfo *info)
{
- guint32 used_flags;
+ guint32 old_flags, new_flags, added_flags, removed_flags;
GObject *summary_object;
- guint32 old_saved_count, old_unread_count, old_deleted_count, old_junk_count;
- guint32 old_junk_not_deleted_count, old_visible_count;
+ gboolean changed = FALSE;
g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
g_return_val_if_fail (info != NULL, FALSE);
@@ -819,38 +853,41 @@ folder_summary_replace_flags (CamelFolderSummary *summary,
camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
g_object_freeze_notify (summary_object);
- used_flags = GPOINTER_TO_UINT (g_hash_table_lookup (summary->priv->uids, camel_message_info_uid (info)));
+ old_flags = GPOINTER_TO_UINT (g_hash_table_lookup (summary->priv->uids, camel_message_info_uid (info)));
+ new_flags = camel_message_info_flags (info);
+
+ if ((old_flags & ~CAMEL_MESSAGE_FOLDER_FLAGGED) == (new_flags & ~CAMEL_MESSAGE_FOLDER_FLAGGED)) {
+ g_object_thaw_notify (summary_object);
+ camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+ return FALSE;
+ }
- old_saved_count = summary->priv->saved_count;
- old_unread_count = summary->priv->unread_count;
- old_deleted_count = summary->priv->deleted_count;
- old_junk_count = summary->priv->junk_count;
- old_junk_not_deleted_count = summary->priv->junk_not_deleted_count;
- old_visible_count = summary->priv->visible_count;
+ added_flags = new_flags & (~(old_flags & new_flags));
+ removed_flags = old_flags & (~(old_flags & new_flags));
- /* decrement counts with old flags */
- folder_summary_update_counts_by_flags (summary, used_flags, TRUE);
+ if ((old_flags & CAMEL_MESSAGE_SEEN) == (new_flags & CAMEL_MESSAGE_SEEN)) {
+ /* unread count is different from others, it asks for nonexistence
+ of the flag, thus if it wasn't changed, then simply set it
+ in added/removed, thus there are no false notifications
+ on unread counts */
+ added_flags |= CAMEL_MESSAGE_SEEN;
+ removed_flags |= CAMEL_MESSAGE_SEEN;
+ }
+
+ /* decrement counts with removed flags */
+ changed = folder_summary_update_counts_by_flags (summary, removed_flags, UPDATE_COUNTS_SUB_WITHOUT_TOTAL) || changed;
+ /* increment counts with added flags */
+ changed = folder_summary_update_counts_by_flags (summary, added_flags, UPDATE_COUNTS_ADD_WITHOUT_TOTAL) || changed;
/* update current flags on the summary */
g_hash_table_insert (summary->priv->uids,
(gpointer) camel_pstring_strdup (camel_message_info_uid (info)),
- GUINT_TO_POINTER (camel_message_info_flags (info)));
+ GUINT_TO_POINTER (new_flags));
- /* increment counts with new flags */
- folder_summary_update_counts_by_flags (summary, camel_message_info_flags (info), FALSE);
-
- /* this approach generates false notifications at least for "saved-count",
- * but is it an issue? I suppose not.
- */
g_object_thaw_notify (summary_object);
camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
- return old_saved_count != summary->priv->saved_count ||
- old_unread_count != summary->priv->unread_count ||
- old_deleted_count != summary->priv->deleted_count ||
- old_junk_count != summary->priv->junk_count ||
- old_junk_not_deleted_count != summary->priv->junk_not_deleted_count ||
- old_visible_count != summary->priv->visible_count;
+ return changed;
}
static CamelMessageInfo *
@@ -1051,7 +1088,7 @@ info_set_flags (CamelMessageInfo *info,
if (mi->summary) {
camel_folder_summary_lock (mi->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
g_object_freeze_notify (G_OBJECT (mi->summary));
- counts_changed = folder_summary_replace_flags (mi->summary, info);
+ counts_changed = camel_folder_summary_replace_flags (mi->summary, info);
}
if (!counts_changed && ((old & ~CAMEL_MESSAGE_SYSTEM_MASK) == (mi->flags & ~CAMEL_MESSAGE_SYSTEM_MASK)) && !((set & CAMEL_MESSAGE_JUNK_LEARN) && !(set & CAMEL_MESSAGE_JUNK))) {
@@ -1719,6 +1756,47 @@ camel_folder_summary_free_array (GPtrArray *array)
g_ptr_array_free (array, TRUE);
}
+static void
+cfs_copy_uids_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ const gchar *uid = key;
+ GHashTable *copy_hash = user_data;
+
+ g_hash_table_insert (copy_hash, (gpointer) camel_pstring_strdup (uid), GINT_TO_POINTER (1));
+}
+
+/**
+ * camel_folder_summary_get_hash:
+ * @summary: a #CamelFolderSummary object
+ *
+ * Returns hash of current stored 'uids' in summary, where key is 'uid'
+ * from the string pool, and value is 1. The returned pointer should
+ * be freed with g_hash_table_destroy().
+ *
+ * Note: When searching for values always use uids from the string pool.
+ *
+ * Since: 3.6
+ **/
+GHashTable *
+camel_folder_summary_get_hash (CamelFolderSummary *summary)
+{
+ GHashTable *uids;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), NULL);
+
+ camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ /* using direct hash because of strings being from the string pool */
+ uids = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) camel_pstring_free, NULL);
+ g_hash_table_foreach (summary->priv->uids, cfs_copy_uids_cb, uids);
+
+ camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ return uids;
+}
+
/**
* camel_folder_summary_peek_loaded:
*
@@ -1764,6 +1842,14 @@ message_info_from_uid (CamelFolderSummary *summary,
struct _db_pass_data data;
folder_name = camel_folder_get_full_name (summary->priv->folder);
+
+ if (is_in_memory_summary (summary)) {
+ camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+ g_warning ("%s: Tried to load uid '%s' from DB on in-memory summary of '%s'",
+ G_STRFUNC, uid, folder_name);
+ return NULL;
+ }
+
parent_store = camel_folder_get_parent_store (summary->priv->folder);
cdb = parent_store->cdb_r;
@@ -1956,7 +2042,9 @@ cfs_try_release_memory (CamelFolderSummary *summary)
CamelSession *session;
/* If folder is freed or if the cache is nil then clean up */
- if (!summary->priv->folder || !g_hash_table_size (summary->priv->loaded_infos)) {
+ if (!summary->priv->folder ||
+ !g_hash_table_size (summary->priv->loaded_infos) ||
+ is_in_memory_summary (summary)) {
summary->priv->cache_load_time = 0;
summary->priv->timeout_handle = 0;
return FALSE;
@@ -1982,6 +2070,9 @@ cfs_schedule_info_release_timer (CamelFolderSummary *summary)
{
g_return_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary));
+ if (is_in_memory_summary (summary))
+ return;
+
if (!summary->priv->timeout_handle) {
static gboolean know_can_do = FALSE, can_do = TRUE;
@@ -2027,8 +2118,10 @@ msg_update_preview (const gchar *uid,
/* FIXME Pass a GCancellable */
msg = camel_folder_get_message_sync (folder, uid, NULL, NULL);
if (msg != NULL) {
- if (camel_mime_message_build_preview ((CamelMimePart *) msg, (CamelMessageInfo *) info) && info->preview)
- camel_db_write_preview_record (parent_store->cdb_w, full_name, info->uid, info->preview, NULL);
+ if (camel_mime_message_build_preview ((CamelMimePart *) msg, (CamelMessageInfo *) info) && info->preview) {
+ if (!is_in_memory_summary (folder->summary))
+ camel_db_write_preview_record (parent_store->cdb_w, full_name, info->uid, info->preview, NULL);
+ }
}
camel_message_info_free (info);
}
@@ -2077,6 +2170,7 @@ preview_update (CamelSession *session,
GHashTable *preview_data, *uids_hash;
CamelStore *parent_store;
const gchar *full_name;
+ gboolean is_in_memory = is_in_memory_summary (folder->summary);
gint i;
uids_array = camel_folder_summary_get_array (folder->summary);
@@ -2088,7 +2182,7 @@ preview_update (CamelSession *session,
full_name = camel_folder_get_full_name (folder);
parent_store = camel_folder_get_parent_store (folder);
- preview_data = camel_db_get_folder_preview (parent_store->cdb_r, full_name, NULL);
+ preview_data = is_in_memory ? NULL : camel_db_get_folder_preview (parent_store->cdb_r, full_name, NULL);
if (preview_data) {
g_hash_table_foreach_remove (preview_data, (GHRFunc) fill_mi, folder);
g_hash_table_destroy (preview_data);
@@ -2103,9 +2197,11 @@ preview_update (CamelSession *session,
}
camel_folder_lock (folder, CAMEL_FOLDER_REC_LOCK);
- camel_db_begin_transaction (parent_store->cdb_w, NULL);
+ if (!is_in_memory)
+ camel_db_begin_transaction (parent_store->cdb_w, NULL);
g_hash_table_foreach (uids_hash, (GHFunc) msg_update_preview, folder);
- camel_db_end_transaction (parent_store->cdb_w, NULL);
+ if (!is_in_memory)
+ camel_db_end_transaction (parent_store->cdb_w, NULL);
camel_folder_unlock (folder, CAMEL_FOLDER_REC_LOCK);
camel_folder_free_uids (folder, uids_uncached);
g_hash_table_destroy (uids_hash);
@@ -2128,6 +2224,9 @@ cfs_reload_from_db (CamelFolderSummary *summary,
* load better. */
d(printf ("\ncamel_folder_summary_reload_from_db called \n"));
+ if (is_in_memory_summary (summary))
+ return 0;
+
folder_name = camel_folder_get_full_name (summary->priv->folder);
parent_store = camel_folder_get_parent_store (summary->priv->folder);
session = camel_service_get_session (CAMEL_SERVICE (parent_store));
@@ -2221,6 +2320,9 @@ camel_folder_summary_load_from_db (CamelFolderSummary *summary,
g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
+ if (is_in_memory_summary (summary))
+ return TRUE;
+
camel_folder_summary_save_to_db (summary, NULL);
/* struct _db_pass_data data; */
@@ -2512,6 +2614,9 @@ save_message_infos_to_db (CamelFolderSummary *summary,
const gchar *full_name;
SaveToDBArgs args;
+ if (is_in_memory_summary (summary))
+ return 0;
+
args.error = error;
args.migration = fresh_mirs;
args.progress = 0;
@@ -2567,7 +2672,8 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
g_return_val_if_fail (summary != NULL, FALSE);
- if (!(summary->flags & CAMEL_SUMMARY_DIRTY))
+ if (!(summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) ||
+ is_in_memory_summary (summary))
return TRUE;
parent_store = camel_folder_get_parent_store (summary->priv->folder);
@@ -2585,7 +2691,7 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
}
- summary->flags &= ~CAMEL_SUMMARY_DIRTY;
+ summary->flags &= ~CAMEL_FOLDER_SUMMARY_DIRTY;
count = cfs_count_dirty (summary);
if (!count)
@@ -2594,7 +2700,7 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
ret = save_message_infos_to_db (summary, FALSE, error);
if (ret != 0) {
/* Failed, so lets reset the flag */
- summary->flags |= CAMEL_SUMMARY_DIRTY;
+ summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
return FALSE;
}
@@ -2614,14 +2720,14 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
ret = save_message_infos_to_db (summary, FALSE, error);
if (ret != 0) {
- summary->flags |= CAMEL_SUMMARY_DIRTY;
+ summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
return FALSE;
}
}
record = CAMEL_FOLDER_SUMMARY_GET_CLASS (summary)->summary_header_to_db (summary, error);
if (!record) {
- summary->flags |= CAMEL_SUMMARY_DIRTY;
+ summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
return FALSE;
}
@@ -2633,7 +2739,7 @@ camel_folder_summary_save_to_db (CamelFolderSummary *summary,
if (ret != 0) {
camel_db_abort_transaction (cdb, NULL);
- summary->flags |= CAMEL_SUMMARY_DIRTY;
+ summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
return FALSE;
}
@@ -2656,6 +2762,9 @@ camel_folder_summary_header_save_to_db (CamelFolderSummary *summary,
CamelDB *cdb;
gint ret;
+ if (is_in_memory_summary (summary))
+ return TRUE;
+
parent_store = camel_folder_get_parent_store (summary->priv->folder);
cdb = parent_store->cdb_w;
@@ -2699,6 +2808,9 @@ camel_folder_summary_header_load_from_db (CamelFolderSummary *summary,
d(printf ("\ncamel_folder_summary_header_load_from_db called \n"));
+ if (is_in_memory_summary (summary))
+ return TRUE;
+
camel_folder_summary_save_to_db (summary, NULL);
cdb = store->cdb_r;
@@ -2782,7 +2894,7 @@ camel_folder_summary_add (CamelFolderSummary *summary,
}
base_info = (CamelMessageInfoBase *) info;
- folder_summary_update_counts_by_flags (summary, camel_message_info_flags (info), FALSE);
+ folder_summary_update_counts_by_flags (summary, camel_message_info_flags (info), UPDATE_COUNTS_ADD);
base_info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
base_info->dirty = TRUE;
@@ -2818,7 +2930,7 @@ camel_folder_summary_insert (CamelFolderSummary *summary,
if (!load) {
CamelMessageInfoBase *base_info = (CamelMessageInfoBase *) info;
- folder_summary_update_counts_by_flags (summary, camel_message_info_flags (info), FALSE);
+ folder_summary_update_counts_by_flags (summary, camel_message_info_flags (info), UPDATE_COUNTS_ADD);
base_info->flags |= CAMEL_MESSAGE_FOLDER_FLAGGED;
base_info->dirty = TRUE;
@@ -3100,7 +3212,7 @@ void
camel_folder_summary_touch (CamelFolderSummary *summary)
{
camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
- summary->flags |= CAMEL_SUMMARY_DIRTY;
+ summary->flags |= CAMEL_FOLDER_SUMMARY_DIRTY;
camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
}
@@ -3144,7 +3256,10 @@ camel_folder_summary_clear (CamelFolderSummary *summary,
parent_store = camel_folder_get_parent_store (summary->priv->folder);
cdb = parent_store->cdb_w;
- res = camel_db_clear_folder_summary (cdb, folder_name, error) == 0;
+ if (!is_in_memory_summary (summary))
+ res = camel_db_clear_folder_summary (cdb, folder_name, error) == 0;
+ else
+ res = TRUE;
summary_object = G_OBJECT (summary);
g_object_freeze_notify (summary_object);
@@ -3213,16 +3328,18 @@ camel_folder_summary_remove_uid (CamelFolderSummary *summary,
return FALSE;
}
- folder_summary_update_counts_by_flags (summary, GPOINTER_TO_UINT (ptr_flags), TRUE);
+ folder_summary_update_counts_by_flags (summary, GPOINTER_TO_UINT (ptr_flags), UPDATE_COUNTS_SUB);
uid_copy = camel_pstring_strdup (uid);
g_hash_table_remove (summary->priv->uids, uid_copy);
g_hash_table_remove (summary->priv->loaded_infos, uid_copy);
- full_name = camel_folder_get_full_name (summary->priv->folder);
- parent_store = camel_folder_get_parent_store (summary->priv->folder);
- if (camel_db_delete_uid (parent_store->cdb_w, full_name, uid_copy, NULL) != 0)
- res = FALSE;
+ if (!is_in_memory_summary (summary)) {
+ full_name = camel_folder_get_full_name (summary->priv->folder);
+ parent_store = camel_folder_get_parent_store (summary->priv->folder);
+ if (camel_db_delete_uid (parent_store->cdb_w, full_name, uid_copy, NULL) != 0)
+ res = FALSE;
+ }
camel_pstring_free (uid_copy);
@@ -3255,26 +3372,30 @@ camel_folder_summary_remove_uids (CamelFolderSummary *summary,
g_return_val_if_fail (CAMEL_IS_FOLDER_SUMMARY (summary), FALSE);
g_return_val_if_fail (uids != NULL, FALSE);
+ g_object_freeze_notify (G_OBJECT (summary));
camel_folder_summary_lock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
for (l = g_list_first(uids); l; l = g_list_next(l)) {
gpointer ptr_uid = NULL, ptr_flags = NULL;
if (g_hash_table_lookup_extended (summary->priv->uids, l->data, &ptr_uid, &ptr_flags)) {
const gchar *uid_copy = camel_pstring_strdup (l->data);
- folder_summary_update_counts_by_flags (summary, GPOINTER_TO_UINT (ptr_flags), TRUE);
+ folder_summary_update_counts_by_flags (summary, GPOINTER_TO_UINT (ptr_flags), UPDATE_COUNTS_SUB);
g_hash_table_remove (summary->priv->uids, uid_copy);
g_hash_table_remove (summary->priv->loaded_infos, uid_copy);
camel_pstring_free (uid_copy);
}
}
- full_name = camel_folder_get_full_name (summary->priv->folder);
- parent_store = camel_folder_get_parent_store (summary->priv->folder);
- if (camel_db_delete_uids (parent_store->cdb_w, full_name, uids, NULL) != 0)
- res = FALSE;
+ if (is_in_memory_summary (summary)) {
+ full_name = camel_folder_get_full_name (summary->priv->folder);
+ parent_store = camel_folder_get_parent_store (summary->priv->folder);
+ if (camel_db_delete_uids (parent_store->cdb_w, full_name, uids, NULL) != 0)
+ res = FALSE;
+ }
camel_folder_summary_touch (summary);
camel_folder_summary_unlock (summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+ g_object_thaw_notify (G_OBJECT (summary));
return res;
}
diff --git a/camel/camel-folder-summary.h b/camel/camel-folder-summary.h
index dacacab..50f335e 100644
--- a/camel/camel-folder-summary.h
+++ b/camel/camel-folder-summary.h
@@ -214,8 +214,17 @@ struct _CamelMessageInfoBase {
gchar *bodystructure;
};
+/**
+ * CamelFolderSummaryFlags:
+ * @CAMEL_FOLDER_SUMMARY_DIRTY:
+ * There are changes in summary, which should be saved.
+ * @CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY:
+ * Summary with this flag doesn't use DB for storing its content,
+ * it is always created on the fly.
+ **/
typedef enum {
- CAMEL_SUMMARY_DIRTY = 1 << 0
+ CAMEL_FOLDER_SUMMARY_DIRTY = 1 << 0,
+ CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY = 1 << 1
} CamelFolderSummaryFlags;
/**
@@ -419,6 +428,12 @@ CamelMessageInfo * camel_folder_summary_get (CamelFolderSummary *summary,
GPtrArray * camel_folder_summary_get_array (CamelFolderSummary *summary);
void camel_folder_summary_free_array (GPtrArray *array);
+GHashTable * camel_folder_summary_get_hash (CamelFolderSummary *summary);
+
+gboolean camel_folder_summary_replace_flags
+ (CamelFolderSummary *summary,
+ CamelMessageInfo *info);
+
/* Peek from mem only */
CamelMessageInfo * camel_folder_summary_peek_loaded
(CamelFolderSummary *summary,
diff --git a/camel/camel-folder.c b/camel/camel-folder.c
index 633a41a..a1c5525 100644
--- a/camel/camel-folder.c
+++ b/camel/camel-folder.c
@@ -851,6 +851,8 @@ folder_freeze (CamelFolder *folder)
camel_folder_lock (folder, CAMEL_FOLDER_CHANGE_LOCK);
folder->priv->frozen++;
+ if (folder->summary)
+ g_object_freeze_notify (G_OBJECT (folder->summary));
d (printf ("freeze (%p '%s') = %d\n", folder, folder->full_name, folder->priv->frozen));
camel_folder_unlock (folder, CAMEL_FOLDER_CHANGE_LOCK);
@@ -866,6 +868,8 @@ folder_thaw (CamelFolder *folder)
camel_folder_lock (folder, CAMEL_FOLDER_CHANGE_LOCK);
folder->priv->frozen--;
+ if (folder->summary)
+ g_object_thaw_notify (G_OBJECT (folder->summary));
d (printf ("thaw (%p '%s') = %d\n", folder, folder->full_name, folder->priv->frozen));
diff --git a/camel/camel-imapx-server.c b/camel/camel-imapx-server.c
index 9f65e49..a52f521 100644
--- a/camel/camel-imapx-server.c
+++ b/camel/camel-imapx-server.c
@@ -5109,7 +5109,7 @@ imapx_command_sync_changes_done (CamelIMAPXServer *is,
}
if (job->commands == 0) {
- if (job->folder->summary && (job->folder->summary->flags & CAMEL_SUMMARY_DIRTY) != 0) {
+ if (job->folder->summary && (job->folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
CamelStoreInfo *si;
/* ... and store's summary when folder's summary is dirty */
diff --git a/camel/camel-store.c b/camel/camel-store.c
index 8e55069..12fa79d 100644
--- a/camel/camel-store.c
+++ b/camel/camel-store.c
@@ -213,7 +213,7 @@ cs_delete_cached_folder (CamelStore *store,
vfolder = camel_object_bag_get (
store->folders, CAMEL_VTRASH_NAME);
if (vfolder != NULL) {
- camel_vee_folder_remove_folder (vfolder, folder);
+ camel_vee_folder_remove_folder (vfolder, folder, NULL);
g_object_unref (vfolder);
}
}
@@ -222,7 +222,7 @@ cs_delete_cached_folder (CamelStore *store,
vfolder = camel_object_bag_get (
store->folders, CAMEL_VJUNK_NAME);
if (vfolder != NULL) {
- camel_vee_folder_remove_folder (vfolder, folder);
+ camel_vee_folder_remove_folder (vfolder, folder, NULL);
g_object_unref (vfolder);
}
}
@@ -245,7 +245,7 @@ store_get_special (CamelStore *store,
folders = camel_object_bag_list (store->folders);
for (i = 0; i < folders->len; i++) {
if (!CAMEL_IS_VTRASH_FOLDER (folders->pdata[i]))
- camel_vee_folder_add_folder ((CamelVeeFolder *) folder, (CamelFolder *) folders->pdata[i]);
+ camel_vee_folder_add_folder ((CamelVeeFolder *) folder, (CamelFolder *) folders->pdata[i], NULL);
g_object_unref (folders->pdata[i]);
}
g_ptr_array_free (folders, TRUE);
@@ -402,8 +402,7 @@ store_synchronize_sync (CamelStore *store,
camel_folder_synchronize_sync (
folder, expunge, cancellable, &local_error);
ignore_no_such_table_exception (&local_error);
- } else if (CAMEL_IS_VEE_FOLDER (folder))
- camel_vee_folder_sync_headers (folder, NULL); /* Literally don't care of vfolder exceptions */
+ }
g_object_unref (folder);
}
@@ -1924,7 +1923,7 @@ camel_store_get_folder_sync (CamelStore *store,
* virtual Junk folder, let the virtual Junk folder
* track this folder. */
if (vjunk != NULL) {
- camel_vee_folder_add_folder (vjunk, folder);
+ camel_vee_folder_add_folder (vjunk, folder, NULL);
g_object_unref (vjunk);
}
@@ -1932,7 +1931,7 @@ camel_store_get_folder_sync (CamelStore *store,
* virtual Trash folder, let the virtual Trash folder
* track this folder. */
if (vtrash != NULL) {
- camel_vee_folder_add_folder (vtrash, folder);
+ camel_vee_folder_add_folder (vtrash, folder, NULL);
g_object_unref (vtrash);
}
diff --git a/camel/camel-string-utils.c b/camel/camel-string-utils.c
index 817c1d0..76971d9 100644
--- a/camel/camel-string-utils.c
+++ b/camel/camel-string-utils.c
@@ -161,8 +161,7 @@ camel_pstring_add (gchar *str,
gboolean own)
{
gpointer pcount;
- gchar *pstr;
- gint count;
+ gpointer pstr;
if (str == NULL)
return NULL;
@@ -175,16 +174,18 @@ camel_pstring_add (gchar *str,
g_static_mutex_lock (&pstring_lock);
if (pstring_table == NULL)
- pstring_table = g_hash_table_new (g_str_hash, g_str_equal);
+ pstring_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
- if (g_hash_table_lookup_extended (pstring_table, str, (gpointer *) &pstr, &pcount)) {
- count = GPOINTER_TO_INT (pcount) + 1;
- g_hash_table_insert (pstring_table, pstr, GINT_TO_POINTER (count));
+ if (g_hash_table_lookup_extended (pstring_table, str, &pstr, &pcount)) {
+ gint *count = pcount;
+ *count = (*count) + 1;
if (own)
g_free (str);
} else {
+ gint *count = g_new0 (gint, 1);
+ *count = 1;
pstr = own ? str : g_strdup (str);
- g_hash_table_insert (pstring_table, pstr, GINT_TO_POINTER (1));
+ g_hash_table_insert (pstring_table, pstr, count);
}
g_static_mutex_unlock (&pstring_lock);
@@ -209,7 +210,7 @@ const gchar *
camel_pstring_peek (const gchar *str)
{
gpointer pcount;
- gchar *pstr;
+ gpointer pstr;
if (str == NULL)
return NULL;
@@ -220,11 +221,13 @@ camel_pstring_peek (const gchar *str)
g_static_mutex_lock (&pstring_lock);
if (pstring_table == NULL)
- pstring_table = g_hash_table_new (g_str_hash, g_str_equal);
+ pstring_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
- if (!g_hash_table_lookup_extended (pstring_table, str, (gpointer *) &pstr, &pcount)) {
+ if (!g_hash_table_lookup_extended (pstring_table, str, &pstr, &pcount)) {
+ gint *count = g_new0 (gint, 1);
+ *count = 1;
pstr = g_strdup (str);
- g_hash_table_insert (pstring_table, pstr, GINT_TO_POINTER (1));
+ g_hash_table_insert (pstring_table, pstr, count);
}
g_static_mutex_unlock (&pstring_lock);
@@ -262,9 +265,8 @@ camel_pstring_strdup (const gchar *s)
void
camel_pstring_free (const gchar *s)
{
- gchar *p;
+ gpointer pstr;
gpointer pcount;
- gint count;
if (pstring_table == NULL)
return;
@@ -272,17 +274,16 @@ camel_pstring_free (const gchar *s)
return;
g_static_mutex_lock (&pstring_lock);
- if (g_hash_table_lookup_extended (pstring_table, s, (gpointer *) &p, &pcount)) {
- count = GPOINTER_TO_INT (pcount) - 1;
- if (count == 0) {
- g_hash_table_remove (pstring_table, p);
- g_free (p);
+ if (g_hash_table_lookup_extended (pstring_table, s, &pstr, &pcount)) {
+ gint *count = pcount;
+ *count = (*count) - 1;
+ if ((*count) == 0) {
+ g_hash_table_remove (pstring_table, pstr);
+ g_free (pstr);
if (g_getenv("CDS_DEBUG")) {
- if (p != s) /* Only for debugging purposes */
+ if (pstr != s) /* Only for debugging purposes */
g_assert (0);
}
- } else {
- g_hash_table_insert (pstring_table, p, GINT_TO_POINTER (count));
}
} else {
if (g_getenv("CDS_DEBUG")) {
@@ -293,3 +294,39 @@ camel_pstring_free (const gchar *s)
}
g_static_mutex_unlock (&pstring_lock);
}
+
+static void
+count_pstring_memory_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ const gchar *str = key;
+ guint64 *pbytes = user_data;
+
+ g_return_if_fail (str != NULL);
+ g_return_if_fail (pbytes != NULL);
+
+ *pbytes += strlen (str);
+}
+
+/**
+ * camel_pstring_dump_stat:
+ *
+ * Dumps to stdout memory statistic about the string pool.
+ **/
+void
+camel_pstring_dump_stat (void)
+{
+ g_static_mutex_lock (&pstring_lock);
+
+ if (!pstring_table) {
+ g_print (" String Pool Statistics: Not used yet\n");
+ } else {
+ guint64 bytes = 0;
+
+ g_hash_table_foreach (pstring_table, count_pstring_memory_cb, &bytes);
+ g_print (" String Pool Statistics: Holds %d strings of total %" G_GUINT64_FORMAT " bytes\n", g_hash_table_size (pstring_table), bytes);
+ }
+
+ g_static_mutex_unlock (&pstring_lock);
+}
diff --git a/camel/camel-string-utils.h b/camel/camel-string-utils.h
index c84ca38..d6b11e6 100644
--- a/camel/camel-string-utils.h
+++ b/camel/camel-string-utils.h
@@ -46,6 +46,7 @@ const gchar *camel_pstring_add (gchar *str, gboolean own);
const gchar *camel_pstring_strdup (const gchar *s);
void camel_pstring_free (const gchar *s);
const gchar * camel_pstring_peek (const gchar *str);
+void camel_pstring_dump_stat (void);
G_END_DECLS
diff --git a/camel/camel-subscribable.c b/camel/camel-subscribable.c
index 0bb193b..ba1eed0 100644
--- a/camel/camel-subscribable.c
+++ b/camel/camel-subscribable.c
@@ -110,7 +110,7 @@ subscribable_delete_cached_folder (CamelStore *store,
folder_name = CAMEL_VTRASH_NAME;
vfolder = camel_object_bag_get (store->folders, folder_name);
if (vfolder != NULL) {
- camel_vee_folder_remove_folder (vfolder, folder);
+ camel_vee_folder_remove_folder (vfolder, folder, NULL);
g_object_unref (vfolder);
}
}
@@ -119,7 +119,7 @@ subscribable_delete_cached_folder (CamelStore *store,
folder_name = CAMEL_VJUNK_NAME;
vfolder = camel_object_bag_get (store->folders, folder_name);
if (vfolder != NULL) {
- camel_vee_folder_remove_folder (vfolder, folder);
+ camel_vee_folder_remove_folder (vfolder, folder, NULL);
g_object_unref (vfolder);
}
}
diff --git a/camel/camel-vee-data-cache.c b/camel/camel-vee-data-cache.c
new file mode 100644
index 0000000..b0a1284
--- /dev/null
+++ b/camel/camel-vee-data-cache.c
@@ -0,0 +1,638 @@
+/*
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "camel-string-utils.h"
+#include "camel-store.h"
+
+#include "camel-vee-data-cache.h"
+
+struct _CamelVeeSubfolderDataPrivate
+{
+ CamelFolder *folder;
+ const gchar *folder_id; /* stored in string pool */
+};
+
+G_DEFINE_TYPE (CamelVeeSubfolderData, camel_vee_subfolder_data, G_TYPE_OBJECT)
+
+static void
+camel_vee_subfolder_data_dispose (GObject *object)
+{
+ CamelVeeSubfolderData *data;
+
+ data = CAMEL_VEE_SUBFOLDER_DATA (object);
+ if (data->priv) {
+ if (data->priv->folder)
+ g_object_unref (data->priv->folder);
+ data->priv->folder = NULL;
+
+ if (data->priv->folder_id)
+ camel_pstring_free (data->priv->folder_id);
+ data->priv->folder_id = NULL;
+ }
+
+ /* Chain up to parent's dispose () method. */
+ G_OBJECT_CLASS (camel_vee_subfolder_data_parent_class)->dispose (object);
+}
+
+static void
+camel_vee_subfolder_data_class_init (CamelVeeSubfolderDataClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (CamelVeeSubfolderDataPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = camel_vee_subfolder_data_dispose;
+}
+
+static void
+camel_vee_subfolder_data_init (CamelVeeSubfolderData *data)
+{
+ data->priv = G_TYPE_INSTANCE_GET_PRIVATE (data, CAMEL_TYPE_VEE_SUBFOLDER_DATA, CamelVeeSubfolderDataPrivate);
+}
+
+static void
+vee_subfolder_data_hash_folder (CamelFolder *folder,
+ gchar buffer[8])
+{
+ CamelStore *parent_store;
+ GChecksum *checksum;
+ guint8 *digest;
+ gsize length;
+ gint state = 0, save = 0;
+ gchar *ptr_string;
+ const gchar *uid;
+ gint i;
+
+ length = g_checksum_type_get_length (G_CHECKSUM_MD5);
+ digest = g_alloca (length);
+
+ checksum = g_checksum_new (G_CHECKSUM_MD5);
+ parent_store = camel_folder_get_parent_store (folder);
+ uid = camel_service_get_uid (CAMEL_SERVICE (parent_store));
+ g_checksum_update (checksum, (guchar *) uid, -1);
+
+ ptr_string = g_strdup_printf ("%p", folder);
+ g_checksum_update (checksum, (guchar *) ptr_string, -1);
+ g_free (ptr_string);
+
+ g_checksum_get_digest (checksum, digest, &length);
+ g_checksum_free (checksum);
+
+ g_base64_encode_step (digest, 6, FALSE, buffer, &state, &save);
+ g_base64_encode_close (FALSE, buffer, &state, &save);
+
+ for (i = 0; i < 8; i++) {
+ if (buffer[i] == '+')
+ buffer[i] = '.';
+ if (buffer[i] == '/')
+ buffer[i] = '_';
+ }
+}
+
+CamelVeeSubfolderData *
+camel_vee_subfolder_data_new (CamelFolder *folder)
+{
+ CamelVeeSubfolderData *data;
+ gchar buffer[8], *folder_id;
+
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+
+ data = g_object_new (CAMEL_TYPE_VEE_SUBFOLDER_DATA, NULL);
+ data->priv->folder = g_object_ref (folder);
+
+ vee_subfolder_data_hash_folder (folder, buffer);
+ folder_id = g_strndup (buffer, 8);
+
+ data->priv->folder_id = camel_pstring_add (folder_id, TRUE);
+
+ return data;
+}
+
+CamelFolder *
+camel_vee_subfolder_data_get_folder (CamelVeeSubfolderData *data)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_SUBFOLDER_DATA (data), NULL);
+
+ return data->priv->folder;
+}
+
+const gchar *
+camel_vee_subfolder_data_get_folder_id (CamelVeeSubfolderData *data)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_SUBFOLDER_DATA (data), NULL);
+
+ return data->priv->folder_id;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct _CamelVeeMessageInfoDataPrivate
+{
+ CamelVeeSubfolderData *subfolder_data;
+ const gchar *orig_message_uid; /* stored in string pool */
+ const gchar *vee_message_uid; /* stored in string pool */
+};
+
+G_DEFINE_TYPE (CamelVeeMessageInfoData, camel_vee_message_info_data, G_TYPE_OBJECT)
+
+static void
+camel_vee_message_info_data_dispose (GObject *object)
+{
+ CamelVeeMessageInfoData *data;
+
+ data = CAMEL_VEE_MESSAGE_INFO_DATA (object);
+ if (data->priv) {
+ if (data->priv->subfolder_data)
+ g_object_unref (data->priv->subfolder_data);
+ data->priv->subfolder_data = NULL;
+
+ if (data->priv->orig_message_uid)
+ camel_pstring_free (data->priv->orig_message_uid);
+ data->priv->orig_message_uid = NULL;
+
+ if (data->priv->vee_message_uid)
+ camel_pstring_free (data->priv->vee_message_uid);
+ data->priv->vee_message_uid = NULL;
+ }
+
+ /* Chain up to parent's dispose () method. */
+ G_OBJECT_CLASS (camel_vee_message_info_data_parent_class)->dispose (object);
+}
+
+static void
+camel_vee_message_info_data_class_init (CamelVeeMessageInfoDataClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (CamelVeeMessageInfoDataPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = camel_vee_message_info_data_dispose;
+}
+
+static void
+camel_vee_message_info_data_init (CamelVeeMessageInfoData *data)
+{
+ data->priv = G_TYPE_INSTANCE_GET_PRIVATE (data, CAMEL_TYPE_VEE_MESSAGE_INFO_DATA, CamelVeeMessageInfoDataPrivate);
+}
+
+CamelVeeMessageInfoData *
+camel_vee_message_info_data_new (CamelVeeSubfolderData *subfolder_data,
+ const gchar *orig_message_uid)
+{
+ CamelVeeMessageInfoData *data;
+ gchar *vee_message_uid;
+
+ g_return_val_if_fail (CAMEL_IS_VEE_SUBFOLDER_DATA (subfolder_data), NULL);
+ g_return_val_if_fail (orig_message_uid != NULL, NULL);
+
+ data = g_object_new (CAMEL_TYPE_VEE_MESSAGE_INFO_DATA, NULL);
+ data->priv->subfolder_data = g_object_ref (subfolder_data);
+
+ vee_message_uid = g_strconcat (camel_vee_subfolder_data_get_folder_id (subfolder_data), orig_message_uid, NULL);
+
+ data->priv->orig_message_uid = camel_pstring_strdup (orig_message_uid);
+ data->priv->vee_message_uid = camel_pstring_add (vee_message_uid, TRUE);
+
+ return data;
+}
+
+CamelVeeSubfolderData *
+camel_vee_message_info_data_get_subfolder_data (CamelVeeMessageInfoData *data)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (data), NULL);
+
+ return data->priv->subfolder_data;
+}
+
+const gchar *
+camel_vee_message_info_data_get_orig_message_uid (CamelVeeMessageInfoData *data)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (data), NULL);
+
+ return data->priv->orig_message_uid;
+}
+
+const gchar *
+camel_vee_message_info_data_get_vee_message_uid (CamelVeeMessageInfoData *data)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (data), NULL);
+
+ return data->priv->vee_message_uid;
+}
+
+/* ----------------------------------------------------------------------- */
+
+struct _CamelVeeDataCachePrivate
+{
+ GMutex *sf_mutex; /* guards subfolder_hash */
+ GHashTable *subfolder_hash; /* CamelFolder * => CamelVeeSubfolderData * */
+
+ GMutex *mi_mutex; /* guards message_info_hash */
+ GHashTable *orig_message_uid_hash; /* VeeData * => CamelVeeMessageInfoData * */
+ GHashTable *vee_message_uid_hash; /* const gchar *vee_uid => CamelVeeMessageInfoData * */
+};
+
+G_DEFINE_TYPE (CamelVeeDataCache, camel_vee_data_cache, G_TYPE_OBJECT)
+
+typedef struct _VeeData
+{
+ CamelFolder *folder;
+ const gchar *orig_message_uid;
+} VeeData;
+
+static guint
+vee_data_hash (gconstpointer ptr)
+{
+ const VeeData *vee_data = ptr;
+
+ if (!vee_data)
+ return 0;
+
+ return g_direct_hash (vee_data->folder)
+ + g_str_hash (vee_data->orig_message_uid);
+}
+
+static gboolean
+vee_data_equal (gconstpointer v1,
+ gconstpointer v2)
+{
+ const VeeData *vee_data1 = v1, *vee_data2 = v2;
+
+ if (!v1 || !v2)
+ return v1 == v2;
+
+ /* can contain ponters directly, strings are always from the string pool */
+ return v1 == v2 ||
+ (vee_data1->folder == vee_data2->folder &&
+ vee_data1->orig_message_uid == vee_data2->orig_message_uid);
+}
+
+static void
+camel_vee_data_cache_dispose (GObject *object)
+{
+ CamelVeeDataCache *data_cache;
+
+ data_cache = CAMEL_VEE_DATA_CACHE (object);
+ if (data_cache->priv) {
+ if (data_cache->priv->subfolder_hash)
+ g_hash_table_destroy (data_cache->priv->subfolder_hash);
+ data_cache->priv->subfolder_hash = NULL;
+
+ if (data_cache->priv->orig_message_uid_hash)
+ g_hash_table_destroy (data_cache->priv->orig_message_uid_hash);
+ data_cache->priv->orig_message_uid_hash = NULL;
+
+ if (data_cache->priv->vee_message_uid_hash)
+ g_hash_table_destroy (data_cache->priv->vee_message_uid_hash);
+ data_cache->priv->vee_message_uid_hash = NULL;
+
+ if (data_cache->priv->sf_mutex)
+ g_mutex_free (data_cache->priv->sf_mutex);
+ data_cache->priv->sf_mutex = NULL;
+
+ if (data_cache->priv->mi_mutex)
+ g_mutex_free (data_cache->priv->mi_mutex);
+ data_cache->priv->mi_mutex = NULL;
+ }
+
+ /* Chain up to parent's dispose () method. */
+ G_OBJECT_CLASS (camel_vee_data_cache_parent_class)->dispose (object);
+}
+
+static void
+camel_vee_data_cache_class_init (CamelVeeDataCacheClass *class)
+{
+ GObjectClass *object_class;
+
+ g_type_class_add_private (class, sizeof (CamelVeeDataCachePrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->dispose = camel_vee_data_cache_dispose;
+}
+
+static void
+camel_vee_data_cache_init (CamelVeeDataCache *data_cache)
+{
+ data_cache->priv = G_TYPE_INSTANCE_GET_PRIVATE (data_cache, CAMEL_TYPE_VEE_DATA_CACHE, CamelVeeDataCachePrivate);
+
+ data_cache->priv->sf_mutex = g_mutex_new ();
+ data_cache->priv->subfolder_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
+
+ data_cache->priv->mi_mutex = g_mutex_new ();
+ data_cache->priv->orig_message_uid_hash = g_hash_table_new_full (vee_data_hash, vee_data_equal, g_free, g_object_unref);
+ data_cache->priv->vee_message_uid_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+}
+
+CamelVeeDataCache *
+camel_vee_data_cache_new (void)
+{
+ return g_object_new (CAMEL_TYPE_VEE_DATA_CACHE, NULL);
+}
+
+void
+camel_vee_data_cache_add_subfolder (CamelVeeDataCache *data_cache,
+ CamelFolder *subfolder)
+{
+ CamelVeeSubfolderData *sf_data;
+
+ g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
+ g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
+
+ g_mutex_lock (data_cache->priv->mi_mutex);
+ g_mutex_lock (data_cache->priv->sf_mutex);
+
+ sf_data = g_hash_table_lookup (data_cache->priv->subfolder_hash, subfolder);
+ if (!sf_data) {
+ GPtrArray *uids;
+ gint ii;
+
+ sf_data = camel_vee_subfolder_data_new (subfolder);
+ g_hash_table_insert (data_cache->priv->subfolder_hash, subfolder, sf_data);
+
+ /* camel_vee_data_cache_get_message_info_data() caches uids on demand,
+ while here are cached all known uids in once - it is better when
+ the folder is used in Unmatched folder, where the uid/vuid will
+ be used in the vfolder or Unmatched folder anyway */
+ uids = camel_folder_get_uids (subfolder);
+ if (uids) {
+ for (ii = 0; ii < uids->len; ii++) {
+ VeeData vdata;
+ CamelVeeMessageInfoData *mi_data;
+
+ /* make sure the orig_message_uid comes from the string pool */
+ vdata.folder = subfolder;
+ vdata.orig_message_uid = camel_pstring_strdup (uids->pdata[ii]);
+
+ mi_data = g_hash_table_lookup (data_cache->priv->orig_message_uid_hash, &vdata);
+ if (!mi_data) {
+ VeeData *hash_data;
+
+ mi_data = camel_vee_message_info_data_new (sf_data, vdata.orig_message_uid);
+
+ hash_data = g_new0 (VeeData, 1);
+ hash_data->folder = subfolder;
+ hash_data->orig_message_uid = camel_vee_message_info_data_get_orig_message_uid (mi_data);
+
+ g_hash_table_insert (data_cache->priv->orig_message_uid_hash, hash_data, mi_data);
+ g_hash_table_insert (data_cache->priv->vee_message_uid_hash,
+ (gpointer) camel_vee_message_info_data_get_vee_message_uid (mi_data),
+ mi_data);
+ }
+
+ camel_pstring_free (vdata.orig_message_uid);
+ }
+
+ camel_folder_free_uids (subfolder, uids);
+ }
+ }
+
+ g_mutex_unlock (data_cache->priv->sf_mutex);
+ g_mutex_unlock (data_cache->priv->mi_mutex);
+}
+
+static gboolean
+remove_vee_by_folder_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ CamelVeeMessageInfoData *mi_data = value;
+ CamelVeeSubfolderData *sf_data;
+ CamelFolder *folder = user_data;
+
+ if (!mi_data)
+ return FALSE;
+
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ return sf_data && camel_vee_subfolder_data_get_folder (sf_data) == folder;
+}
+
+static gboolean
+remove_orig_by_folder_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ VeeData *vee_data = key;
+ CamelFolder *folder = user_data;
+
+ return vee_data && vee_data->folder == folder;
+}
+
+void
+camel_vee_data_cache_remove_subfolder (CamelVeeDataCache *data_cache,
+ CamelFolder *subfolder)
+{
+ g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
+ g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
+
+ g_mutex_lock (data_cache->priv->mi_mutex);
+ g_mutex_lock (data_cache->priv->sf_mutex);
+
+ g_hash_table_foreach_remove (data_cache->priv->vee_message_uid_hash, remove_vee_by_folder_cb, subfolder);
+ g_hash_table_foreach_remove (data_cache->priv->orig_message_uid_hash, remove_orig_by_folder_cb, subfolder);
+ g_hash_table_remove (data_cache->priv->subfolder_hash, subfolder);
+
+ g_mutex_unlock (data_cache->priv->sf_mutex);
+ g_mutex_unlock (data_cache->priv->mi_mutex);
+}
+
+CamelVeeSubfolderData *
+camel_vee_data_cache_get_subfolder_data (CamelVeeDataCache *data_cache,
+ CamelFolder *folder)
+{
+ CamelVeeSubfolderData *res;
+
+ g_return_val_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache), NULL);
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+
+ g_mutex_lock (data_cache->priv->sf_mutex);
+
+ res = g_hash_table_lookup (data_cache->priv->subfolder_hash, folder);
+ if (!res) {
+ res = camel_vee_subfolder_data_new (folder);
+ g_hash_table_insert (data_cache->priv->subfolder_hash, folder, res);
+ }
+
+ g_object_ref (res);
+
+ g_mutex_unlock (data_cache->priv->sf_mutex);
+
+ return res;
+}
+
+CamelVeeMessageInfoData *
+camel_vee_data_cache_get_message_info_data (CamelVeeDataCache *data_cache,
+ CamelFolder *folder,
+ const gchar *orig_message_uid)
+{
+ CamelVeeMessageInfoData *res;
+ VeeData vdata;
+
+ g_return_val_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache), NULL);
+ g_return_val_if_fail (CAMEL_IS_FOLDER (folder), NULL);
+ g_return_val_if_fail (orig_message_uid != NULL, NULL);
+
+ g_mutex_lock (data_cache->priv->mi_mutex);
+
+ /* make sure the orig_message_uid comes from the string pool */
+ vdata.folder = folder;
+ vdata.orig_message_uid = camel_pstring_strdup (orig_message_uid);
+
+ res = g_hash_table_lookup (data_cache->priv->orig_message_uid_hash, &vdata);
+ if (!res) {
+ VeeData *hash_data;
+ CamelVeeSubfolderData *sf_data;
+
+ /* this locks also priv->sf_mutex */
+ sf_data = camel_vee_data_cache_get_subfolder_data (data_cache, folder);
+ if (!sf_data) {
+ camel_pstring_free (vdata.orig_message_uid);
+ g_mutex_unlock (data_cache->priv->mi_mutex);
+ g_return_val_if_fail (sf_data != NULL, NULL);
+ }
+
+ res = camel_vee_message_info_data_new (sf_data, orig_message_uid);
+
+ /* res holds the reference now */
+ g_object_unref (sf_data);
+
+ hash_data = g_new0 (VeeData, 1);
+ hash_data->folder = folder;
+ hash_data->orig_message_uid = camel_vee_message_info_data_get_orig_message_uid (res);
+
+ g_hash_table_insert (data_cache->priv->orig_message_uid_hash, hash_data, res);
+ g_hash_table_insert (data_cache->priv->vee_message_uid_hash,
+ (gpointer) camel_vee_message_info_data_get_vee_message_uid (res),
+ res);
+ }
+
+ camel_pstring_free (vdata.orig_message_uid);
+ g_object_ref (res);
+
+ g_mutex_unlock (data_cache->priv->mi_mutex);
+
+ return res;
+}
+
+CamelVeeMessageInfoData *
+camel_vee_data_cache_get_message_info_data_by_vuid (CamelVeeDataCache *data_cache,
+ const gchar *vee_message_uid)
+{
+ CamelVeeMessageInfoData *res;
+ const gchar *vuid;
+
+ g_return_val_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache), NULL);
+ g_return_val_if_fail (vee_message_uid != NULL, NULL);
+
+ g_mutex_lock (data_cache->priv->mi_mutex);
+
+ /* make sure vee_message_uid comes from the string pool */
+ vuid = camel_pstring_strdup (vee_message_uid);
+
+ res = g_hash_table_lookup (data_cache->priv->vee_message_uid_hash, vuid);
+ if (res)
+ g_object_ref (res);
+
+ g_mutex_unlock (data_cache->priv->mi_mutex);
+
+ camel_pstring_free (vuid);
+
+ return res;
+}
+
+struct ForeachMiData
+{
+ CamelFolder *fromfolder;
+ void (* func) (CamelVeeMessageInfoData *mi_data,
+ CamelFolder *subfolder,
+ gpointer user_data);
+ gpointer user_data;
+};
+
+static void
+cvdc_foreach_mi_data_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ VeeData *vdata = key;
+ CamelVeeMessageInfoData *mi_data = value;
+ struct ForeachMiData *fmd = user_data;
+
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (value != NULL);
+ g_return_if_fail (user_data != NULL);
+
+ if (!fmd->fromfolder || fmd->fromfolder == vdata->folder)
+ fmd->func (mi_data, vdata->folder, fmd->user_data);
+}
+
+void
+camel_vee_data_cache_foreach_message_info_data (CamelVeeDataCache *data_cache,
+ CamelFolder *fromfolder,
+ void (* func) (CamelVeeMessageInfoData *mi_data,
+ CamelFolder *subfolder,
+ gpointer user_data),
+ gpointer user_data)
+{
+ struct ForeachMiData fmd;
+
+ g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
+ g_return_if_fail (func != NULL);
+
+ g_mutex_lock (data_cache->priv->mi_mutex);
+
+ fmd.fromfolder = fromfolder;
+ fmd.func = func;
+ fmd.user_data = user_data;
+
+ g_hash_table_foreach (data_cache->priv->orig_message_uid_hash, cvdc_foreach_mi_data_cb, &fmd);
+
+ g_mutex_unlock (data_cache->priv->mi_mutex);
+}
+
+void
+camel_vee_data_cache_remove_message_info_data (CamelVeeDataCache *data_cache,
+ CamelVeeMessageInfoData *mi_data)
+{
+ VeeData vdata;
+ CamelVeeSubfolderData *sf_data;
+ const gchar *vuid;
+
+ g_return_if_fail (CAMEL_IS_VEE_DATA_CACHE (data_cache));
+ g_return_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (mi_data));
+
+ g_mutex_lock (data_cache->priv->mi_mutex);
+
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+
+ vdata.folder = camel_vee_subfolder_data_get_folder (sf_data);
+ vdata.orig_message_uid = camel_vee_message_info_data_get_orig_message_uid (mi_data);
+ vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
+
+ g_hash_table_remove (data_cache->priv->vee_message_uid_hash, vuid);
+ g_hash_table_remove (data_cache->priv->orig_message_uid_hash, &vdata);
+
+ g_mutex_unlock (data_cache->priv->mi_mutex);
+}
diff --git a/camel/camel-vee-data-cache.h b/camel/camel-vee-data-cache.h
new file mode 100644
index 0000000..99249f5
--- /dev/null
+++ b/camel/camel-vee-data-cache.h
@@ -0,0 +1,177 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright (C) 2012 Red Hat, Inc. (www.redhat.com)
+ *
+ * Authors: Milan Crha <mcrha redhat com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU Lesser General Public
+ * License as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this program; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if !defined (__CAMEL_H_INSIDE__) && !defined (CAMEL_COMPILATION)
+#error "Only <camel/camel.h> can be included directly."
+#endif
+
+#ifndef CAMEL_VEE_DATA_CACHE_H
+#define CAMEL_VEE_DATA_CACHE_H
+
+#include <camel/camel-folder.h>
+
+/* Standard GObject macros */
+#define CAMEL_TYPE_VEE_SUBFOLDER_DATA \
+ (camel_vee_subfolder_data_get_type ())
+#define CAMEL_VEE_SUBFOLDER_DATA(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_VEE_SUBFOLDER_DATA, CamelVeeSubfolderData))
+#define CAMEL_VEE_SUBFOLDER_DATA_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_VEE_SUBFOLDER_DATA, CamelVeeSubfolderDataClass))
+#define CAMEL_IS_VEE_SUBFOLDER_DATA(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_VEE_SUBFOLDER_DATA))
+#define CAMEL_IS_VEE_SUBFOLDER_DATA_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_VEE_SUBFOLDER_DATA))
+#define CAMEL_VEE_SUBFOLDER_DATA_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_VEE_SUBFOLDER_DATA, CamelVeeSubfolderDataClass))
+
+#define CAMEL_TYPE_VEE_MESSAGE_INFO_DATA \
+ (camel_vee_message_info_data_get_type ())
+#define CAMEL_VEE_MESSAGE_INFO_DATA(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_VEE_MESSAGE_INFO_DATA, CamelVeeMessageInfoData))
+#define CAMEL_VEE_MESSAGE_INFO_DATA_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_VEE_MESSAGE_INFO_DATA, CamelVeeMessageInfoDataClass))
+#define CAMEL_IS_VEE_MESSAGE_INFO_DATA(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_VEE_MESSAGE_INFO_DATA))
+#define CAMEL_IS_VEE_MESSAGE_INFO_DATA_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_VEE_MESSAGE_INFO_DATA))
+#define CAMEL_VEE_MESSAGE_INFO_DATA_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_VEE_MESSAGE_INFO_DATA, CamelVeeMessageInfoDataClass))
+
+#define CAMEL_TYPE_VEE_DATA_CACHE \
+ (camel_vee_data_cache_get_type ())
+#define CAMEL_VEE_DATA_CACHE(obj) \
+ (G_TYPE_CHECK_INSTANCE_CAST \
+ ((obj), CAMEL_TYPE_VEE_DATA_CACHE, CamelVeeDataCache))
+#define CAMEL_VEE_DATA_CACHE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_CAST \
+ ((cls), CAMEL_TYPE_VEE_DATA_CACHE, CamelVeeDataCacheClass))
+#define CAMEL_IS_VEE_DATA_CACHE(obj) \
+ (G_TYPE_CHECK_INSTANCE_TYPE \
+ ((obj), CAMEL_TYPE_VEE_DATA_CACHE))
+#define CAMEL_IS_VEE_DATA_CACHE_CLASS(cls) \
+ (G_TYPE_CHECK_CLASS_TYPE \
+ ((cls), CAMEL_TYPE_VEE_DATA_CACHE))
+#define CAMEL_VEE_DATA_CACHE_GET_CLASS(obj) \
+ (G_TYPE_INSTANCE_GET_CLASS \
+ ((obj), CAMEL_TYPE_VEE_DATA_CACHE, CamelVeeDataCacheClass))
+
+G_BEGIN_DECLS
+
+typedef struct _CamelVeeSubfolderData CamelVeeSubfolderData;
+typedef struct _CamelVeeSubfolderDataPrivate CamelVeeSubfolderDataPrivate;
+typedef struct _CamelVeeSubfolderDataClass CamelVeeSubfolderDataClass;
+
+typedef struct _CamelVeeMessageInfoData CamelVeeMessageInfoData;
+typedef struct _CamelVeeMessageInfoDataPrivate CamelVeeMessageInfoDataPrivate;
+typedef struct _CamelVeeMessageInfoDataClass CamelVeeMessageInfoDataClass;
+
+typedef struct _CamelVeeDataCache CamelVeeDataCache;
+typedef struct _CamelVeeDataCachePrivate CamelVeeDataCachePrivate;
+typedef struct _CamelVeeDataCacheClass CamelVeeDataCacheClass;
+
+struct _CamelVeeSubfolderData {
+ GObject parent;
+
+ CamelVeeSubfolderDataPrivate *priv;
+};
+
+struct _CamelVeeSubfolderDataClass {
+ GObjectClass parent_class;
+};
+
+GType camel_vee_subfolder_data_get_type (void);
+CamelVeeSubfolderData * camel_vee_subfolder_data_new (CamelFolder *folder);
+CamelFolder * camel_vee_subfolder_data_get_folder (CamelVeeSubfolderData *data); /* returned not reffed */
+const gchar * camel_vee_subfolder_data_get_folder_id (CamelVeeSubfolderData *data);
+
+/* ----------------------------------------------------------------------- */
+
+struct _CamelVeeMessageInfoData {
+ GObject parent;
+
+ CamelVeeMessageInfoDataPrivate *priv;
+};
+
+struct _CamelVeeMessageInfoDataClass {
+ GObjectClass parent_class;
+};
+
+GType camel_vee_message_info_data_get_type (void);
+CamelVeeMessageInfoData * camel_vee_message_info_data_new (CamelVeeSubfolderData *subfolder_data,
+ const gchar *orig_message_uid);
+CamelVeeSubfolderData * camel_vee_message_info_data_get_subfolder_data
+ (CamelVeeMessageInfoData *data); /* returned not reffed */
+const gchar * camel_vee_message_info_data_get_orig_message_uid
+ (CamelVeeMessageInfoData *data);
+const gchar * camel_vee_message_info_data_get_vee_message_uid
+ (CamelVeeMessageInfoData *data);
+
+/* ----------------------------------------------------------------------- */
+
+struct _CamelVeeDataCache {
+ GObject parent;
+
+ CamelVeeDataCachePrivate *priv;
+};
+
+struct _CamelVeeDataCacheClass {
+ GObjectClass parent_class;
+};
+
+GType camel_vee_data_cache_get_type (void);
+CamelVeeDataCache * camel_vee_data_cache_new (void);
+void camel_vee_data_cache_add_subfolder (CamelVeeDataCache *data_cache,
+ CamelFolder *subfolder);
+void camel_vee_data_cache_remove_subfolder (CamelVeeDataCache *data_cache,
+ CamelFolder *subfolder);
+CamelVeeSubfolderData * camel_vee_data_cache_get_subfolder_data (CamelVeeDataCache *data_cache, /* returned is reffed */
+ CamelFolder *folder);
+CamelVeeMessageInfoData * camel_vee_data_cache_get_message_info_data /* returned is reffed */
+ (CamelVeeDataCache *data_cache,
+ CamelFolder *folder,
+ const gchar *orig_message_uid);
+CamelVeeMessageInfoData * camel_vee_data_cache_get_message_info_data_by_vuid /* returned is reffed */
+ (CamelVeeDataCache *data_cache,
+ const gchar *vee_message_uid);
+void camel_vee_data_cache_foreach_message_info_data
+ (CamelVeeDataCache *data_cache,
+ CamelFolder *fromfolder,
+ void (* func) (CamelVeeMessageInfoData *mi_data,
+ CamelFolder *subfolder,
+ gpointer user_data),
+ gpointer user_data);
+void camel_vee_data_cache_remove_message_info_data
+ (CamelVeeDataCache *data_cache,
+ CamelVeeMessageInfoData *mi_data);
+
+G_END_DECLS
+
+#endif /* CAMEL_VEE_DATA_CACHE_H */
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c
index c66b40a..82aa589 100644
--- a/camel/camel-vee-folder.c
+++ b/camel/camel-vee-folder.c
@@ -51,585 +51,417 @@ typedef struct _FolderChangedData FolderChangedData;
struct _CamelVeeFolderPrivate {
gboolean destroyed;
- GList *folders; /* lock using subfolder_lock before changing/accessing */
- GList *folders_changed; /* for list of folders that have changed between updates */
+ GList *subfolders; /* lock using subfolder_lock before changing/accessing */
GHashTable *ignore_changed; /* hash of subfolder pointers to ignore the next folder's 'changed' signal */
GHashTable *skipped_changes; /* CamelFolder -> CamelFolderChangeInfo accumulating ignored changes */
+ GHashTable *unmatched_add_changed; /* CamelVeeMessageInfoData -> 1, for unmatched folder, postponed additions from camel_vee_folder_add_vuid() */
+ GHashTable *unmatched_remove_changed; /* CamelVeeMessageInfoData -> 1, for unmatched folder, postponed removal from camel_vee_folder_remove_vuid() */
+ gboolean auto_update;
/* Processing queue for folder changes. */
GAsyncQueue *change_queue;
gboolean change_queue_busy;
- GMutex *summary_lock; /* for locking vfolder summary */
- GMutex *subfolder_lock; /* for locking the subfolder list */
- GMutex *changed_lock; /* for locking the folders-changed list */
+ GStaticRecMutex summary_lock; /* for locking vfolder summary */
+ GStaticRecMutex subfolder_lock; /* for locking the subfolder list */
+ GStaticRecMutex changed_lock; /* for locking the folders-changed list */
+
+ gchar *expression; /* query expression */
+
+ /* only set-up if our parent is a vee-store, used also as a flag to
+ * say that this folder is part of the unmatched folder */
+ CamelVeeStore *parent_vee_store;
+
+ CamelVeeDataCache *vee_data_cache;
};
-struct _update_data {
- CamelFolder *source;
- CamelVeeFolder *vee_folder;
- gchar hash[8];
- CamelVeeFolder *folder_unmatched;
- GHashTable *unmatched_uids;
- gboolean rebuilt, correlating;
-
- /* used for uids that needs to be updated in db later by unmatched_check_uid and
- * folder_added_uid */
- GQueue *message_uids;
+/* The custom property ID is a CamelArg artifact.
+ * It still identifies the property in state files. */
+enum {
+ PROP_0,
+ PROP_AUTO_UPDATE = 0x2401
};
+G_DEFINE_TYPE (CamelVeeFolder, camel_vee_folder, CAMEL_TYPE_FOLDER)
+
struct _FolderChangedData {
CamelFolderChangeInfo *changes;
- CamelFolder *sub;
+ CamelFolder *subfolder;
};
-G_DEFINE_TYPE (CamelVeeFolder, camel_vee_folder, CAMEL_TYPE_FOLDER)
+static FolderChangedData *
+vee_folder_changed_data_new (CamelFolder *subfolder,
+ CamelFolderChangeInfo *changes)
+{
+ FolderChangedData *data;
+
+ data = g_slice_new0 (FolderChangedData);
+ data->changes = camel_folder_change_info_new ();
+ camel_folder_change_info_cat (data->changes, changes);
+ data->subfolder = g_object_ref (subfolder);
+
+ return data;
+}
static void
-folder_changed_data_free (FolderChangedData *data)
+vee_folder_changed_data_free (FolderChangedData *data)
{
camel_folder_change_info_free (data->changes);
- g_object_unref (data->sub);
+ g_object_unref (data->subfolder);
g_slice_free (FolderChangedData, data);
}
-/* must be called with summary_lock held */
-static CamelVeeMessageInfo *
-vee_folder_add_uid (CamelVeeFolder *vf,
- CamelFolder *f,
- const gchar *inuid,
- const gchar hash[8])
+static CamelVeeDataCache *
+vee_folder_get_data_cache (CamelVeeFolder *vfolder)
{
- CamelVeeMessageInfo *mi = NULL;
+ g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (vfolder), NULL);
+
+ if (vfolder->priv->parent_vee_store)
+ return camel_vee_store_get_vee_data_cache (vfolder->priv->parent_vee_store);
- mi = camel_vee_summary_add ((CamelVeeSummary *)((CamelFolder *) vf)->summary, f->summary, (gchar *) inuid, hash);
- return mi;
+ return vfolder->priv->vee_data_cache;
}
-/* same as vee_folder_add_uid, only returns whether uid was added or not */
static gboolean
-vee_folder_add_uid_test (CamelVeeFolder *vf,
- CamelFolder *f,
- const gchar *inuid,
- const gchar hash[8])
+vee_folder_is_unmatched (CamelVeeFolder *vfolder)
{
- CamelVeeMessageInfo *mi;
-
- mi = vee_folder_add_uid (vf, f, inuid, hash);
+ g_return_val_if_fail (vfolder != NULL, FALSE);
- if (mi != NULL)
- camel_message_info_free ((CamelMessageInfo *) mi);
-
- return mi != NULL;
+ return vfolder->priv->parent_vee_store &&
+ vfolder == camel_vee_store_get_unmatched_folder (vfolder->priv->parent_vee_store);
}
-/* A "correlating" expression has the property that whether a message matches
- * depends on the other messages being searched. folder_changed_change on a
- * vfolder with a correlating expression may not make all the necessary updates,
- * so the query is redone on the entire changed source folder the next time
- * the vfolder is opened.
- *
- * The only current example of a correlating expression is one that uses
- * "match-threads". */
-static gboolean
-expression_is_correlating (const gchar *expr)
+static void
+vee_folder_note_added_uid (CamelVeeFolder *vfolder,
+ CamelVeeSummary *vsummary,
+ CamelVeeMessageInfoData *added_mi_data,
+ CamelFolderChangeInfo *changes,
+ gboolean included_as_changed)
{
- /* XXX: Actually parse the expression to avoid triggering on
- * "match-threads" in the text the user is searching for! */
- return (strstr (expr, "match-threads") != NULL);
+ const gchar *vuid;
+
+ vuid = camel_vee_message_info_data_get_vee_message_uid (added_mi_data);
+ if (!camel_folder_summary_check_uid (&vsummary->summary, vuid)) {
+ /* add it only if it wasn't in yet */
+ CamelVeeMessageInfo *vmi;
+
+ vmi = camel_vee_summary_add (vsummary, added_mi_data);
+ if (vmi) {
+ if (changes)
+ camel_folder_change_info_add_uid (changes, vuid);
+ camel_message_info_free (vmi);
+
+ if (vfolder->priv->parent_vee_store)
+ camel_vee_store_note_vuid_used (vfolder->priv->parent_vee_store, added_mi_data, vfolder);
+ }
+ } else {
+ camel_vee_summary_replace_flags (vsummary, vuid);
+ if (included_as_changed && changes)
+ camel_folder_change_info_change_uid (changes, vuid);
+ }
}
-/* Hold all these with summary lock and unmatched summary lock held */
static void
-folder_changed_add_uid (CamelFolder *sub,
- const gchar *uid,
- const gchar hash[8],
- CamelVeeFolder *vf,
- gboolean use_db,
- GList **m_added_l,
- GList **unm_added_l)
+vee_folder_note_unmatch_uid (CamelVeeFolder *vfolder,
+ CamelVeeSummary *vsummary,
+ CamelFolder *subfolder,
+ CamelVeeMessageInfoData *unmatched_mi_data,
+ CamelFolderChangeInfo *changes)
{
- CamelVeeMessageInfo *vinfo;
const gchar *vuid;
- gchar *oldkey;
- gpointer oldval;
- gint n;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
- GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
-
- vinfo = vee_folder_add_uid (vf, sub, uid, hash);
- if (vinfo == NULL)
- return;
- vuid = camel_pstring_strdup (camel_message_info_uid (vinfo));
- camel_message_info_free ((CamelMessageInfo *) vinfo);
+ vuid = camel_vee_message_info_data_get_vee_message_uid (unmatched_mi_data);
+ if (camel_folder_summary_check_uid (&vsummary->summary, vuid)) {
+ g_object_ref (unmatched_mi_data);
- if (use_db)
- *m_added_l = g_list_prepend (*m_added_l, (gpointer) camel_pstring_strdup (vuid));
+ /* this one doesn't belong to us anymore */
+ if (changes)
+ camel_folder_change_info_remove_uid (changes, vuid);
+ camel_vee_summary_remove (vsummary, vuid, subfolder);
- camel_folder_change_info_add_uid (vf->changes, vuid);
- if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER (sub) && folder_unmatched != NULL) {
- if (g_hash_table_lookup_extended (unmatched_uids, vuid, (gpointer *) &oldkey, &oldval)) {
- n = GPOINTER_TO_INT (oldval);
- g_hash_table_insert (unmatched_uids, oldkey, GINT_TO_POINTER (n + 1));
- } else {
- g_hash_table_insert (unmatched_uids, g_strdup (vuid), GINT_TO_POINTER (1));
- }
- vinfo = (CamelVeeMessageInfo *) camel_folder_get_message_info ((CamelFolder *) folder_unmatched, vuid);
- if (vinfo) {
- camel_folder_change_info_remove_uid (
- folder_unmatched->changes, vuid);
-
- *unm_added_l = g_list_prepend (*unm_added_l, (gpointer) camel_pstring_strdup (vuid));
-
- camel_folder_summary_remove_uid (
- CAMEL_FOLDER (folder_unmatched)->summary, vuid);
- camel_folder_free_message_info (
- CAMEL_FOLDER (folder_unmatched),
- (CamelMessageInfo *) vinfo);
- }
- }
+ if (vfolder->priv->parent_vee_store)
+ camel_vee_store_note_vuid_unused (vfolder->priv->parent_vee_store, unmatched_mi_data, vfolder);
- camel_pstring_free (vuid);
+ g_object_unref (unmatched_mi_data);
+ }
}
static void
-folder_changed_remove_uid (CamelFolder *sub,
- const gchar *uid,
- const gchar hash[8],
- gint keep,
- CamelVeeFolder *vf,
- gboolean use_db,
- GList **m_removed_l,
- GList **unm_removed_l)
+vee_folder_remove_unmatched (CamelVeeFolder *vfolder,
+ CamelVeeSummary *vsummary,
+ CamelVeeDataCache *data_cache,
+ CamelFolderChangeInfo *changes,
+ CamelFolder *subfolder,
+ const gchar *orig_message_uid,
+ gboolean is_orig_message_uid) /* if not, then it's 'vee_message_uid' */
{
- CamelFolder *folder = (CamelFolder *) vf;
- gchar *vuid, *oldkey;
- gpointer oldval;
- gint n;
- CamelVeeMessageInfo *vinfo;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
- GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
-
- vuid = alloca (strlen (uid) + 9);
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
-
- camel_folder_change_info_remove_uid (vf->changes, vuid);
- if (use_db)
- *m_removed_l = g_list_prepend (*m_removed_l, (gpointer) camel_pstring_strdup (vuid));
-
- camel_folder_summary_remove_uid (folder->summary, vuid);
-
- if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER (sub) && folder_unmatched != NULL) {
- if (keep) {
- if (g_hash_table_lookup_extended (unmatched_uids, vuid, (gpointer *) &oldkey, &oldval)) {
- n = GPOINTER_TO_INT (oldval);
- if (n == 1) {
- g_hash_table_remove (unmatched_uids, oldkey);
- if (vee_folder_add_uid_test (folder_unmatched, sub, uid, hash))
- camel_folder_change_info_add_uid (folder_unmatched->changes, oldkey);
- g_free (oldkey);
- } else {
- g_hash_table_insert (unmatched_uids, oldkey, GINT_TO_POINTER (n - 1));
- }
- } else {
- if (vee_folder_add_uid_test (folder_unmatched, sub, uid, hash))
- camel_folder_change_info_add_uid (folder_unmatched->changes, vuid);
- }
- } else {
- if (g_hash_table_lookup_extended (unmatched_uids, vuid, (gpointer *) &oldkey, &oldval)) {
- g_hash_table_remove (unmatched_uids, oldkey);
- g_free (oldkey);
- }
+ CamelVeeMessageInfoData *mi_data;
- vinfo = (CamelVeeMessageInfo *) camel_folder_get_message_info ((CamelFolder *) folder_unmatched, vuid);
- if (vinfo) {
- camel_folder_change_info_remove_uid (
- folder_unmatched->changes, vuid);
+ if (is_orig_message_uid)
+ mi_data = camel_vee_data_cache_get_message_info_data (data_cache, subfolder, orig_message_uid);
+ else
+ mi_data = camel_vee_data_cache_get_message_info_data_by_vuid (data_cache, orig_message_uid);
- *unm_removed_l = g_list_prepend (*unm_removed_l, (gpointer) camel_pstring_strdup (vuid));
+ if (!mi_data)
+ return;
- camel_folder_summary_remove_uid (
- CAMEL_FOLDER (folder_unmatched)->summary, vuid);
- camel_folder_free_message_info (
- CAMEL_FOLDER (folder_unmatched),
- (CamelMessageInfo *) vinfo);
- }
- }
- }
+ vee_folder_note_unmatch_uid (vfolder, vsummary, subfolder, mi_data, changes);
+
+ g_object_unref (mi_data);
}
+struct RemoveUnmatchedData
+{
+ CamelVeeFolder *vfolder;
+ CamelVeeSummary *vsummary;
+ CamelFolder *subfolder;
+ CamelVeeDataCache *data_cache;
+ CamelFolderChangeInfo *changes;
+ gboolean is_orig_message_uid;
+};
+
static void
-folder_changed_change_uid (CamelFolder *sub,
- const gchar *uid,
- const gchar hash[8],
- CamelVeeFolder *vf,
- gboolean use_db,
- GList **m_removed_l,
- GList **unm_removed_l)
+vee_folder_remove_unmatched_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
{
- gchar *vuid;
- CamelVeeMessageInfo *vinfo, *uinfo = NULL;
- CamelMessageInfo *info;
- CamelFolder *folder = (CamelFolder *) vf;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
-
- vuid = alloca (strlen (uid) + 9);
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
-
- vinfo = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, vuid);
- if (folder_unmatched != NULL)
- uinfo = (CamelVeeMessageInfo *) camel_folder_summary_get (((CamelFolder *) folder_unmatched)->summary, vuid);
- if (vinfo || uinfo) {
- info = camel_folder_get_message_info (sub, uid);
- if (info) {
- if (vinfo) {
- camel_folder_change_info_change_uid (vf->changes, vuid);
- vinfo->old_flags = camel_message_info_flags ((CamelMessageInfo *) vinfo);
- vinfo->info.flags |= (vinfo->old_flags & ~CAMEL_MESSAGE_FOLDER_FLAGGED);
- camel_message_info_free ((CamelMessageInfo *) vinfo);
- }
+ struct RemoveUnmatchedData *rud = user_data;
+ const gchar *uid = key;
- if (uinfo) {
- camel_folder_change_info_change_uid (folder_unmatched->changes, vuid);
- uinfo->old_flags = camel_message_info_flags ((CamelMessageInfo *) uinfo);
- uinfo->info.flags |= (uinfo->old_flags & ~CAMEL_MESSAGE_FOLDER_FLAGGED);
- camel_message_info_free ((CamelMessageInfo *) uinfo);
- }
+ g_return_if_fail (rud != NULL);
- camel_folder_free_message_info (sub, info);
- } else {
- if (vinfo) {
- folder_changed_remove_uid (sub, uid, hash, FALSE, vf, use_db, m_removed_l, unm_removed_l);
- camel_message_info_free ((CamelMessageInfo *) vinfo);
- }
- if (uinfo)
- camel_message_info_free ((CamelMessageInfo *) uinfo);
- }
- }
+ vee_folder_remove_unmatched (rud->vfolder, rud->vsummary, rud->data_cache, rud->changes, rud->subfolder, uid, rud->is_orig_message_uid);
}
static void
-vfolder_add_remove_transaction (CamelStore *parent_store,
- const gchar *full_name,
- GList **uids,
- gboolean add,
- GError **error)
+vee_folder_merge_matching (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GHashTable *all_uids,
+ GPtrArray *match,
+ CamelFolderChangeInfo *changes,
+ gboolean included_as_changed)
{
- GList *l;
+ CamelVeeDataCache *data_cache;
+ CamelVeeMessageInfoData *mi_data;
+ CamelFolder *folder;
+ CamelVeeSummary *vsummary;
+ struct RemoveUnmatchedData rud;
+ gint ii;
- for (l = *uids; l != NULL; l = g_list_next (l)) {
- if (add)
- camel_db_add_to_vfolder_transaction (parent_store->cdb_w, full_name,
- (const gchar *) l->data, error);
- else
- camel_db_delete_uid_from_vfolder_transaction
- (parent_store->cdb_w, full_name,
- (const gchar *) l->data, error);
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
+ g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
+ g_return_if_fail (all_uids != NULL);
+ g_return_if_fail (match != NULL);
+
+ folder = CAMEL_FOLDER (vfolder);
+ g_return_if_fail (folder != NULL);
+
+ vsummary = CAMEL_VEE_SUMMARY (folder->summary);
+ g_return_if_fail (vsummary != NULL);
+
+ data_cache = vee_folder_get_data_cache (vfolder);
+ for (ii = 0; ii < match->len; ii++) {
+ const gchar *uid = match->pdata[ii];
+
+ mi_data = camel_vee_data_cache_get_message_info_data (data_cache, subfolder, uid);
+ if (!mi_data)
+ continue;
+
+ g_hash_table_remove (all_uids, uid);
+
+ vee_folder_note_added_uid (vfolder, vsummary, mi_data, changes, included_as_changed);
+
+ g_object_unref (mi_data);
}
- g_list_foreach (*uids, (GFunc) camel_pstring_free, NULL);
- g_list_free (*uids);
- *uids = NULL;
+ rud.vfolder = vfolder;
+ rud.vsummary = vsummary;
+ rud.subfolder = subfolder;
+ rud.data_cache = data_cache;
+ rud.changes = changes;
+ rud.is_orig_message_uid = TRUE;
+
+ /* in 'all_uids' left only those which are not part of the folder anymore */
+ g_hash_table_foreach (all_uids, vee_folder_remove_unmatched_cb, &rud);
}
static void
-folder_changed_change (CamelVeeFolder *vf,
- GCancellable *cancellable,
- FolderChangedData *data,
- GError **error)
+vee_folder_rebuild_folder_with_changes (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ CamelFolderChangeInfo *changes,
+ GCancellable *cancellable)
{
- CamelFolder *sub = data->sub;
- CamelFolder *folder = CAMEL_FOLDER (vf);
- CamelFolderChangeInfo *changes = data->changes;
- gchar *vuid = NULL, hash[8];
- const gchar *uid;
- CamelVeeMessageInfo *vinfo;
- gint i, vuidlen = 0;
- CamelFolderChangeInfo *vf_changes = NULL, *unmatched_changes = NULL;
- GPtrArray *matches_added = NULL, /* newly added, that match */
- *matches_changed = NULL, /* newly changed, that now match */
- *newchanged = NULL,
- *changed;
- GPtrArray *always_changed = NULL;
- GHashTable *matches_hash;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
- GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
- GPtrArray *present = NULL;
- GList *m_added_l = NULL, *m_removed_l = NULL, *unm_added_l = NULL, *unm_removed_l = NULL;
-
- /* See vee_folder_rebuild_folder. */
- gboolean correlating = expression_is_correlating (vf->expression);
-
- /* Check the folder hasn't beem removed while we weren't watching */
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- if (g_list_find (CAMEL_VEE_FOLDER_GET_PRIVATE (vf)->folders, sub) == NULL) {
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- return;
- }
+ GPtrArray *match = NULL;
- camel_vee_folder_hash_folder (sub, hash);
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
+ g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
- /* Lookup anything before we lock anything, to avoid deadlock with build_folder */
+ /* Unmatched folder cannot be rebuilt */
+ if (vee_folder_is_unmatched (vfolder))
+ return;
- /* Find newly added that match */
- if (changes->uid_added->len > 0) {
- dd (printf (" Searching for added matches '%s'\n", vf->expression));
- matches_added = camel_folder_search_by_uids (sub, vf->expression, changes->uid_added, cancellable, NULL);
+ /* if we have no expression, or its been cleared, then act as if no matches */
+ if (vfolder->priv->expression == NULL) {
+ match = g_ptr_array_new ();
+ } else {
+ match = camel_folder_search_by_expression (subfolder, vfolder->priv->expression, cancellable, NULL);
+ if (!match)
+ return;
}
- /* TODO:
- * In this code around here, we can work out if the search will affect the changes
- * we had, and only re-search against them if they might have */
-
- /* Search for changed items that newly match, but only if we dont have them */
- changed = changes->uid_changed;
- if (changed->len > 0) {
- dd (printf (" Searching for changed matches '%s'\n", vf->expression));
-
- if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) {
- newchanged = g_ptr_array_new ();
- always_changed = g_ptr_array_new ();
- for (i = 0; i < changed->len; i++) {
- uid = changed->pdata[i];
- if (!vuid || strlen (uid) + 9 > vuidlen) {
- vuidlen = strlen (uid) + 64;
- vuid = g_realloc (vuid, vuidlen);
- }
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
- vinfo = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, vuid);
- if (vinfo == NULL) {
- g_ptr_array_add (newchanged, (gchar *) uid);
- } else {
- g_ptr_array_add (always_changed, (gchar *) uid);
- camel_message_info_free ((CamelMessageInfo *) vinfo);
- }
- }
- changed = newchanged;
- }
+ if (!g_cancellable_is_cancelled (cancellable)) {
+ GHashTable *all_uids;
- if (changed->len)
- matches_changed = camel_folder_search_by_uids (sub, vf->expression, changed, cancellable, NULL);
- if (always_changed && always_changed->len)
- present = camel_folder_search_by_uids (sub, vf->expression, always_changed, cancellable, NULL);
+ all_uids = camel_folder_summary_get_hash (subfolder->summary);
+ vee_folder_merge_matching (vfolder, subfolder, all_uids, match, changes, FALSE);
+ g_hash_table_destroy (all_uids);
}
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
+ camel_folder_search_free (subfolder, match);
+}
- if (folder_unmatched != NULL)
- camel_vee_folder_lock (folder_unmatched, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
+static void
+vee_folder_rebuild_all (CamelVeeFolder *vfolder,
+ GCancellable *cancellable)
+{
+ CamelFolderChangeInfo *changes;
+ GList *iter;
- /* Always remove removed uid's, in any case */
- for (i = 0; i < changes->uid_removed->len; i++) {
- dd (printf (" removing uid '%s'\n", (gchar *)changes->uid_removed->pdata[i]));
- folder_changed_remove_uid (sub, changes->uid_removed->pdata[i], hash, FALSE, vf, !correlating, &m_removed_l, &unm_removed_l);
- }
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
- /* Add any newly matched or to unmatched folder if they dont */
- if (matches_added) {
- matches_hash = g_hash_table_new (g_str_hash, g_str_equal);
- for (i = 0; i < matches_added->len; i++) {
- dd (printf (" %s", (gchar *)matches_added->pdata[i]));
- g_hash_table_insert (matches_hash, matches_added->pdata[i], matches_added->pdata[i]);
- }
- for (i = 0; i < changes->uid_added->len; i++) {
- uid = changes->uid_added->pdata[i];
- if (g_hash_table_lookup (matches_hash, uid)) {
- dd (printf (" adding uid '%s' [newly matched]\n", (gchar *)uid));
- folder_changed_add_uid (sub, uid, hash, vf, !correlating, &m_added_l, &unm_added_l);
- } else if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
- if (strlen (uid) + 9 > vuidlen) {
- vuidlen = strlen (uid) + 64;
- vuid = g_realloc (vuid, vuidlen);
- }
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
-
- if (!CAMEL_IS_VEE_FOLDER (sub) && folder_unmatched != NULL && g_hash_table_lookup (unmatched_uids, vuid) == NULL) {
- dd (printf (" adding uid '%s' to Unmatched [newly unmatched]\n", (gchar *)uid));
- vinfo = (CamelVeeMessageInfo *) camel_folder_get_message_info ((CamelFolder *) folder_unmatched, vuid);
- if (vinfo == NULL) {
- if (vee_folder_add_uid_test (folder_unmatched, sub, uid, hash))
- camel_folder_change_info_add_uid (folder_unmatched->changes, vuid);
- } else {
- camel_folder_free_message_info ((CamelFolder *) folder_unmatched, (CamelMessageInfo *) vinfo);
- }
- }
- }
- }
- g_hash_table_destroy (matches_hash);
- }
+ /* Unmatched folder cannot be rebuilt */
+ if (vee_folder_is_unmatched (vfolder))
+ return;
- /* Change any newly changed */
- if (always_changed) {
- if (correlating) {
- /* Messages may be pulled in by the correlation even if
- * they do not match the expression individually, so it
- * would be wrong to preemptively remove anything here.
- * vee_folder_rebuild_folder will make any necessary removals
- * when it re-queries the entire source folder. */
- for (i = 0; i < always_changed->len; i++)
- folder_changed_change_uid (sub, always_changed->pdata[i], hash, vf, !correlating, &m_removed_l, &unm_removed_l);
- } else {
- GHashTable *ht_present = g_hash_table_new (g_str_hash, g_str_equal);
+ changes = camel_folder_change_info_new ();
- for (i = 0; present && i < present->len; i++) {
- folder_changed_change_uid (sub, present->pdata[i], hash, vf, !correlating, &m_removed_l, &unm_removed_l);
- g_hash_table_insert (ht_present, present->pdata[i], present->pdata[i]);
- }
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- for (i = 0; i < always_changed->len; i++) {
- if (!present || !g_hash_table_lookup (ht_present, always_changed->pdata[i]))
- /* XXX: IIUC, these messages haven't been deleted from the
- * source folder, so shouldn't "keep" be set to TRUE? */
- folder_changed_remove_uid (sub, always_changed->pdata[i], hash, TRUE, vf, !correlating, &m_removed_l, &unm_removed_l);
- }
+ for (iter = vfolder->priv->subfolders;
+ iter && !g_cancellable_is_cancelled (cancellable);
+ iter = iter->next) {
+ CamelFolder *subfolder = iter->data;
- g_hash_table_destroy (ht_present);
- }
- g_ptr_array_free (always_changed, TRUE);
+ vee_folder_rebuild_folder_with_changes (vfolder, subfolder, changes, cancellable);
}
- /* Change/add/remove any changed */
- if (changes->uid_changed->len) {
- /* If we are auto-updating, then re-check changed uids still match */
- dd (printf (" Vfolder %supdate\nuids match:", (vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO)?"auto-":""));
- matches_hash = g_hash_table_new (g_str_hash, g_str_equal);
- for (i = 0; matches_changed && i < matches_changed->len; i++) {
- dd (printf (" %s", (gchar *)matches_changed->pdata[i]));
- g_hash_table_insert (matches_hash, matches_changed->pdata[i], matches_changed->pdata[i]);
- }
- dd (printf ("\n"));
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- for (i = 0; i < changed->len; i++) {
- uid = changed->pdata[i];
- if (strlen (uid) + 9 > vuidlen) {
- vuidlen = strlen (uid) + 64;
- vuid = g_realloc (vuid, vuidlen);
- }
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
- vinfo = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, vuid);
- if (vinfo == NULL) {
- if (g_hash_table_lookup (matches_hash, uid)) {
- /* A uid we dont have, but now it matches, add it */
- dd (printf (" adding uid '%s' [newly matched]\n", uid));
- folder_changed_add_uid (sub, uid, hash, vf, !correlating, &m_added_l, &unm_added_l);
- } else {
- /* A uid we still don't have, just change it (for unmatched) */
- folder_changed_change_uid (sub, uid, hash, vf, !correlating, &m_removed_l, &unm_removed_l);
- }
- } else {
- if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0
- || g_hash_table_lookup (matches_hash, uid)) {
- /* still match, or we're not auto-updating, change event, (if it changed) */
- dd (printf (" changing uid '%s' [still matches]\n", uid));
- folder_changed_change_uid (sub, uid, hash, vf, !correlating, &m_removed_l, &unm_removed_l);
- } else {
- /* No longer matches, remove it, but keep it in unmatched (potentially) */
- dd (printf (" removing uid '%s' [did match]\n", uid));
- folder_changed_remove_uid (sub, uid, hash, TRUE, vf, !correlating, &m_removed_l, &unm_removed_l);
- }
- camel_message_info_free ((CamelMessageInfo *) vinfo);
- }
- }
- g_hash_table_destroy (matches_hash);
- } else {
- /* stuff didn't match but it changed - check unmatched folder for changes */
- for (i = 0; i < changed->len; i++)
- folder_changed_change_uid (sub, changed->pdata[i], hash, vf, !correlating, &m_removed_l, &unm_removed_l);
- }
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (CAMEL_FOLDER (vfolder), changes);
+ camel_folder_change_info_free (changes);
+}
- if (folder_unmatched != NULL) {
- if (camel_folder_change_info_changed (folder_unmatched->changes)) {
- unmatched_changes = folder_unmatched->changes;
- folder_unmatched->changes = camel_folder_change_info_new ();
- }
+static void
+vee_folder_subfolder_changed (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ CamelFolderChangeInfo *subfolder_changes,
+ GCancellable *cancellable,
+ GError **error)
+{
+ CamelVeeDataCache *data_cache;
+ CamelFolderChangeInfo *changes;
+ CamelFolder *v_folder;
+ CamelVeeSummary *vsummary;
+ gint ii;
- camel_vee_folder_unlock (folder_unmatched, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
- }
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
+ g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
+ g_return_if_fail (subfolder_changes != NULL);
- if (camel_folder_change_info_changed (vf->changes)) {
- vf_changes = vf->changes;
- vf->changes = camel_folder_change_info_new ();
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ if (!g_list_find (vfolder->priv->subfolders, subfolder)){
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ return;
}
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+
+ changes = camel_folder_change_info_new ();
+ data_cache = vee_folder_get_data_cache (vfolder);
+ v_folder = CAMEL_FOLDER (vfolder);
+ vsummary = CAMEL_VEE_SUMMARY (v_folder->summary);
- if (matches_changed || matches_added || changes->uid_removed->len || present) {
- const gchar *full_name;
- const gchar *unm_full_name = NULL;
- CamelStore *parent_store;
+ camel_folder_freeze (v_folder);
- parent_store = camel_folder_get_parent_store (folder);
- full_name = camel_folder_get_full_name (folder);
+ for (ii = 0; ii < subfolder_changes->uid_removed->len; ii++) {
+ const gchar *orig_message_uid = subfolder_changes->uid_removed->pdata[ii];
- if (folder_unmatched)
- unm_full_name = camel_folder_get_full_name (CAMEL_FOLDER (folder_unmatched));
+ vee_folder_remove_unmatched (vfolder, vsummary, data_cache, changes, subfolder, orig_message_uid, TRUE);
+ }
- camel_db_begin_transaction (parent_store->cdb_w, NULL);
+ if (subfolder_changes->uid_added->len + subfolder_changes->uid_changed->len > 0) {
+ GPtrArray *test_uids, *match;
+ gboolean my_match = FALSE;
- if (m_added_l)
- vfolder_add_remove_transaction (parent_store, full_name, &m_added_l, TRUE, NULL);
- if (m_removed_l)
- vfolder_add_remove_transaction (parent_store, full_name, &m_removed_l, FALSE, NULL);
- if (unm_added_l)
- vfolder_add_remove_transaction (parent_store, unm_full_name, &unm_added_l, TRUE, NULL);
- if (unm_removed_l)
- vfolder_add_remove_transaction (parent_store, unm_full_name, &unm_removed_l, FALSE, NULL);
+ test_uids = g_ptr_array_sized_new (subfolder_changes->uid_added->len + subfolder_changes->uid_changed->len);
- camel_db_end_transaction (parent_store->cdb_w, NULL);
- }
+ for (ii = 0; ii < subfolder_changes->uid_added->len; ii++) {
+ g_ptr_array_add (test_uids, subfolder_changes->uid_added->pdata[ii]);
+ }
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
+ for (ii = 0; ii < subfolder_changes->uid_changed->len; ii++) {
+ g_ptr_array_add (test_uids, subfolder_changes->uid_changed->pdata[ii]);
+ }
- /* Cleanup stuff on our folder */
- if (matches_added)
- camel_folder_search_free (sub, matches_added);
- if (present)
- camel_folder_search_free (sub, present);
+ if (!vfolder->priv->expression) {
+ my_match = TRUE;
+ match = g_ptr_array_new ();
+
+ if (vee_folder_is_unmatched (vfolder)) {
+ CamelVeeMessageInfoData *mi_data;
+ const gchar *vuid;
+
+ /* all common from test_uids and stored uids
+ in the unmatched folder should be updated */
+ for (ii = 0; ii < test_uids->len; ii++) {
+ mi_data = camel_vee_data_cache_get_message_info_data (data_cache, subfolder, test_uids->pdata[ii]);
+ if (!mi_data)
+ continue;
+
+ vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
+ if (camel_folder_summary_check_uid (v_folder->summary, vuid))
+ g_ptr_array_add (match, (gpointer) camel_pstring_strdup (test_uids->pdata[ii]));
+ g_object_unref (mi_data);
+ }
+ }
+ } else {
+ /* sadly, if there are threads involved, then searching by uids doesn't work,
+ because just changed uids can be brought in by the thread condition */
+ if (strstr (vfolder->priv->expression, "match-threads") != NULL)
+ match = camel_folder_search_by_expression (subfolder, vfolder->priv->expression, cancellable, NULL);
+ else
+ match = camel_folder_search_by_uids (subfolder, vfolder->priv->expression, test_uids, cancellable, NULL);
+ }
- if (matches_changed)
- camel_folder_search_free (sub, matches_changed);
+ if (match) {
+ GHashTable *with_uids;
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ /* uids are taken from the string pool, thus use direct hashes */
+ with_uids = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) camel_pstring_free, NULL);
+ for (ii = 0; ii < test_uids->len; ii++) {
+ g_hash_table_insert (with_uids, (gpointer) camel_pstring_strdup (test_uids->pdata[ii]), GINT_TO_POINTER (1));
+ }
- /* cleanup the rest */
- if (newchanged)
- g_ptr_array_free (newchanged, TRUE);
+ vee_folder_merge_matching (vfolder, subfolder, with_uids, match, changes, TRUE);
- g_free (vuid);
+ g_hash_table_destroy (with_uids);
+ if (my_match) {
+ g_ptr_array_foreach (match, (GFunc) camel_pstring_free, NULL);
+ g_ptr_array_free (match, TRUE);
+ } else {
+ camel_folder_search_free (subfolder, match);
+ }
+ }
- if (unmatched_changes) {
- camel_folder_changed (
- CAMEL_FOLDER (folder_unmatched), unmatched_changes);
- camel_folder_change_info_free (unmatched_changes);
+ g_ptr_array_free (test_uids, TRUE);
}
- /* Add to folders_changed if we need to call vee_folder_rebuild_folder, which
- * could be the case for two reasons:
- * - We changed the vfolder and it is not auto-updating. Need to re-sync.
- * - Vfolder is correlating. Changes to non-matching source messages
- * won't be processed here and won't show up in vf_changes but may
- * still affect the vfolder contents (e.g., non-matching messages
- * added to a matching thread), so we re-run the query on the whole
- * source folder. (For match-threads, it may be enough to do this if
- * changes->uid_added->len > 0, but I'm not completely sure and I'd
- * rather be safe than sorry.)
- */
- if ((vf_changes && (vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0) || correlating) {
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- if (g_list_find (vf->priv->folders_changed, sub) == NULL)
- vf->priv->folders_changed = g_list_prepend (vf->priv->folders_changed, sub);
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- }
+ camel_folder_thaw (v_folder);
- if (vf_changes) {
- camel_folder_changed (CAMEL_FOLDER (vf), vf_changes);
- camel_folder_change_info_free (vf_changes);
- }
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (v_folder, changes);
+ camel_folder_change_info_free (changes);
}
static void
@@ -652,8 +484,8 @@ vee_folder_process_changes (CamelSession *session,
cancellable, _("Updating %s folder"), display_name);
while ((data = g_async_queue_try_pop (change_queue)) != NULL) {
- folder_changed_change (vee_folder, cancellable, data, error);
- folder_changed_data_free (data);
+ vee_folder_subfolder_changed (vee_folder, data->subfolder, data->changes, cancellable, error);
+ vee_folder_changed_data_free (data);
if (g_cancellable_is_cancelled (cancellable))
break;
@@ -665,295 +497,41 @@ vee_folder_process_changes (CamelSession *session,
}
static void
-subfolder_renamed_update (CamelVeeFolder *vf,
- CamelFolder *sub,
- gchar hash[8])
-{
- gint i;
- CamelFolderChangeInfo *changes = NULL;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
- GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
- CamelFolderSummary *ssummary = sub->summary;
- GPtrArray *known_uids;
-
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
-
- camel_folder_summary_prepare_fetch_all (((CamelFolder *) vf)->summary, NULL);
-
- known_uids = camel_folder_summary_get_array (((CamelFolder *) vf)->summary);
- for (i = 0; known_uids && i < known_uids->len; i++) {
- CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) camel_folder_summary_get (((CamelFolder *) vf)->summary, g_ptr_array_index (known_uids, i));
- CamelVeeMessageInfo *vinfo;
-
- if (mi == NULL)
- continue;
-
- if (mi->orig_summary == ssummary) {
- gchar *uid = (gchar *) camel_message_info_uid (mi);
- gchar *oldkey;
- gpointer oldval;
-
- camel_folder_change_info_remove_uid (vf->changes, uid);
- camel_folder_summary_remove (((CamelFolder *) vf)->summary, (CamelMessageInfo *) mi);
-
- vinfo = vee_folder_add_uid (vf, sub, uid + 8, hash);
- if (vinfo) {
- camel_folder_change_info_add_uid (vf->changes, camel_message_info_uid (vinfo));
-
- /* check unmatched uid's table for any matches */
- if (vf == folder_unmatched
- && g_hash_table_lookup_extended (unmatched_uids, uid, (gpointer *) &oldkey, &oldval)) {
- g_hash_table_remove (unmatched_uids, oldkey);
- g_hash_table_insert (unmatched_uids, g_strdup (camel_message_info_uid (vinfo)), oldval);
- g_free (oldkey);
- }
-
- camel_message_info_free ((CamelMessageInfo *) vinfo);
- }
- }
-
- camel_message_info_free ((CamelMessageInfo *) mi);
- }
-
- camel_folder_summary_free_array (known_uids);
-
- if (camel_folder_change_info_changed (vf->changes)) {
- changes = vf->changes;
- vf->changes = camel_folder_change_info_new ();
- }
-
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
-
- if (changes) {
- camel_folder_changed (CAMEL_FOLDER (vf), changes);
- camel_folder_change_info_free (changes);
- }
-}
-
-static gint
-vee_folder_rebuild_folder (CamelVeeFolder *vee_folder,
- CamelFolder *source,
- GError **error);
-
-static void
-unmatched_check_uid (gchar *uidin,
- gpointer value,
- struct _update_data *u)
-{
- gchar *uid;
- gint n;
-
- uid = alloca (strlen (uidin) + 9);
- memcpy (uid, u->hash, 8);
- strcpy (uid + 8, uidin);
- n = GPOINTER_TO_INT (g_hash_table_lookup (u->unmatched_uids, uid));
- if (n == 0) {
- if (vee_folder_add_uid_test (u->folder_unmatched, u->source, uidin, u->hash))
- camel_folder_change_info_add_uid (u->folder_unmatched->changes, uid);
- } else {
- CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) camel_folder_summary_get (((CamelFolder *) u->folder_unmatched)->summary, uid);
- if (mi) {
- if (u->message_uids != NULL)
- g_queue_push_tail (u->message_uids, g_strdup (uid));
-
- camel_folder_summary_remove_uid (
- ((CamelFolder *) u->folder_unmatched)->summary, uid);
- camel_folder_change_info_remove_uid (
- u->folder_unmatched->changes, uid);
- camel_message_info_free ((CamelMessageInfo *) mi);
- }
- }
-}
-
-static void
-folder_added_uid (gchar *uidin,
- gpointer value,
- struct _update_data *u)
-{
- CamelVeeMessageInfo *mi;
- gchar *oldkey;
- gpointer oldval;
- const gchar *uid;
- gint n;
-
- mi = vee_folder_add_uid (u->vee_folder, u->source, uidin, u->hash);
- if (mi == NULL)
- return;
-
- uid = camel_message_info_uid (mi);
-
- if (u->message_uids != NULL)
- g_queue_push_tail (u->message_uids, g_strdup (uid));
-
- camel_folder_change_info_add_uid (u->vee_folder->changes, uid);
-
- if (!CAMEL_IS_VEE_FOLDER (u->source) && u->unmatched_uids != NULL) {
- gboolean found_uid;
-
- found_uid = g_hash_table_lookup_extended (
- u->unmatched_uids, uid,
- (gpointer *) &oldkey, &oldval);
-
- if (found_uid) {
- n = GPOINTER_TO_INT (oldval);
- g_hash_table_insert (
- u->unmatched_uids,
- oldkey, GINT_TO_POINTER (n + 1));
- } else {
- g_hash_table_insert (
- u->unmatched_uids,
- g_strdup (uid), GINT_TO_POINTER (1));
- }
- }
-
- camel_message_info_free ((CamelMessageInfo *) mi);
-}
-
-static CamelFIRecord *
-summary_header_to_db (CamelFolderSummary *s,
- GError **error)
+subfolder_changed (CamelFolder *subfolder,
+ CamelFolderChangeInfo *changes,
+ CamelVeeFolder *vfolder)
{
- CamelFIRecord * record = g_new0 (CamelFIRecord, 1);
- const gchar *full_name;
-
- /* We do this during write, so lets use write handle, though we gonna read */
- full_name = camel_folder_get_full_name (camel_folder_summary_get_folder (s));
+ g_return_if_fail (vfolder != NULL);
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
- record->folder_name = g_strdup (full_name);
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ if (g_hash_table_lookup (vfolder->priv->ignore_changed, subfolder) ||
+ !camel_vee_folder_get_auto_update (vfolder)) {
+ CamelFolderChangeInfo *my_changes;
- /* we always write out the current version */
- record->version = 13; /* FIXME: CAMEL_FOLDER_SUMMARY_VERSION; */
- record->flags = s->flags;
- record->nextuid = camel_folder_summary_get_next_uid (s);
- record->time = s->time;
+ g_hash_table_remove (vfolder->priv->ignore_changed, subfolder);
- record->saved_count = camel_folder_summary_count (s);
- record->junk_count = camel_folder_summary_get_junk_count (s);
- record->deleted_count = camel_folder_summary_get_deleted_count (s);
- record->unread_count = camel_folder_summary_get_unread_count (s);
- record->visible_count = camel_folder_summary_get_visible_count (s);
- record->jnd_count = camel_folder_summary_get_junk_not_deleted_count (s);
+ my_changes = g_hash_table_lookup (vfolder->priv->skipped_changes, subfolder);
+ if (!my_changes)
+ my_changes = camel_folder_change_info_new ();
+ camel_folder_change_info_cat (my_changes, changes);
+ g_hash_table_insert (vfolder->priv->skipped_changes, subfolder, my_changes);
- return record;
-}
-
-static void
-folder_changed (CamelFolder *sub,
- CamelFolderChangeInfo *changes,
- CamelVeeFolder *vee_folder)
-{
- CamelVeeFolderClass *class;
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- g_return_if_fail (vee_folder != NULL);
- g_return_if_fail (CAMEL_IS_VEE_FOLDER (vee_folder));
-
- camel_vee_folder_lock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- if (g_hash_table_lookup (vee_folder->priv->ignore_changed, sub)) {
- CamelFolderChangeInfo *old_changes;
- g_hash_table_remove (vee_folder->priv->ignore_changed, sub);
-
- old_changes = g_hash_table_lookup (vee_folder->priv->skipped_changes, sub);
- if (!old_changes)
- old_changes = camel_folder_change_info_new ();
- camel_folder_change_info_cat (old_changes, changes);
- g_hash_table_insert (vee_folder->priv->skipped_changes, sub, old_changes);
- camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
return;
}
- camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- class = CAMEL_VEE_FOLDER_GET_CLASS (vee_folder);
- class->folder_changed (vee_folder, sub, changes);
+ CAMEL_VEE_FOLDER_GET_CLASS (vfolder)->folder_changed (vfolder, subfolder, changes);
}
/* track vanishing folders */
static void
-subfolder_deleted (CamelFolder *folder,
- CamelVeeFolder *vee_folder)
+subfolder_deleted (CamelFolder *subfolder,
+ CamelVeeFolder *vfolder)
{
- camel_vee_folder_remove_folder (vee_folder, folder);
-}
-
-static void
-folder_renamed (CamelFolder *sub,
- const gchar *old,
- CamelVeeFolder *vee_folder)
-{
- CamelVeeFolderClass *class;
-
- class = CAMEL_VEE_FOLDER_GET_CLASS (vee_folder);
- class->folder_renamed (vee_folder, sub, old);
-}
-
-static void
-vee_folder_stop_folder (CamelVeeFolder *vf,
- CamelFolder *sub,
- GCancellable *cancellable)
-{
- CamelVeeFolderPrivate *p = CAMEL_VEE_FOLDER_GET_PRIVATE (vf);
- gint i;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
-
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- p->folders_changed = g_list_remove (p->folders_changed, sub);
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
-
- if (g_list_find (p->folders, sub) == NULL) {
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- return;
- }
-
- g_signal_handlers_disconnect_by_func (sub, folder_changed, vf);
- g_signal_handlers_disconnect_by_func (sub, subfolder_deleted, vf);
- g_signal_handlers_disconnect_by_func (sub, folder_renamed, vf);
-
- p->folders = g_list_remove (p->folders, sub);
-
- /* undo the freeze state that we have imposed on this source folder */
- camel_folder_lock (CAMEL_FOLDER (vf), CAMEL_FOLDER_CHANGE_LOCK);
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) vf); i++)
- camel_folder_thaw (sub);
- camel_folder_unlock (CAMEL_FOLDER (vf), CAMEL_FOLDER_CHANGE_LOCK);
-
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-
- if (folder_unmatched != NULL) {
- CamelVeeFolderPrivate *up = CAMEL_VEE_FOLDER_GET_PRIVATE (folder_unmatched);
-
- camel_vee_folder_lock (folder_unmatched, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- /* if folder deleted, then blow it away from unmatched always, and remove all refs to it */
- if (sub->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED) {
- while (g_list_find (up->folders, sub)) {
- up->folders = g_list_remove (up->folders, sub);
- g_object_unref (sub);
-
- /* undo the freeze state that Unmatched has imposed on this source folder */
- camel_folder_lock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) folder_unmatched); i++)
- camel_folder_thaw (sub);
- camel_folder_unlock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- }
- } else if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
- if (g_list_find (up->folders, sub) != NULL) {
- up->folders = g_list_remove (up->folders, sub);
- g_object_unref (sub);
-
- /* undo the freeze state that Unmatched has imposed on this source folder */
- camel_folder_lock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) folder_unmatched); i++)
- camel_folder_thaw (sub);
- camel_folder_unlock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- }
- }
- camel_vee_folder_unlock (folder_unmatched, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- }
-
- if (CAMEL_IS_VEE_FOLDER (sub))
- return;
-
- g_object_unref (sub);
+ camel_vee_folder_remove_folder (vfolder, subfolder, NULL);
}
static void
@@ -965,46 +543,17 @@ vee_folder_dispose (GObject *object)
/* parent's class frees summary on dispose, thus depend on it */
if (folder->summary) {
- CamelVeeFolder *vf;
- CamelVeeFolder *folder_unmatched;
- GList *node;
- CamelFIRecord * record;
-
- vf = CAMEL_VEE_FOLDER (object);
- vf->priv->destroyed = TRUE;
+ CamelVeeFolder *vfolder;
- folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ vfolder = CAMEL_VEE_FOLDER (object);
+ vfolder->priv->destroyed = TRUE;
- /* Save the counts to DB */
- if (!vf->deleted) {
- CamelFolder *folder;
- CamelStore *parent_store;
-
- folder = CAMEL_FOLDER (vf);
- parent_store = camel_folder_get_parent_store (folder);
- record = summary_header_to_db (folder->summary, NULL);
-
- camel_db_begin_transaction (parent_store->cdb_w, NULL);
- camel_db_write_folder_info_record (parent_store->cdb_w, record, NULL);
- camel_db_end_transaction (parent_store->cdb_w, NULL);
-
- g_free (record->folder_name);
- g_free (record);
- }
-
- /* This may invoke sub-classes with partially destroyed state, they must deal with this */
- if (vf == folder_unmatched) {
- for (node = vf->priv->folders; node; node = g_list_next (node))
- g_object_unref (node->data);
- } else {
- /* FIXME[disk-summary] See if it is really reqd */
- camel_folder_freeze ((CamelFolder *) vf);
- while (vf->priv->folders) {
- CamelFolder *f = vf->priv->folders->data;
- vee_folder_stop_folder (vf, f, NULL);
- }
- camel_folder_thaw ((CamelFolder *) vf);
+ camel_folder_freeze ((CamelFolder *) vfolder);
+ while (vfolder->priv->subfolders) {
+ CamelFolder *subfolder = vfolder->priv->subfolders->data;
+ camel_vee_folder_remove_folder (vfolder, subfolder, NULL);
}
+ camel_folder_thaw ((CamelFolder *) vfolder);
}
/* Chain up to parent's dispose () method. */
@@ -1026,33 +575,69 @@ vee_folder_finalize (GObject *object)
vf = CAMEL_VEE_FOLDER (object);
- g_free (vf->expression);
+ g_free (vf->priv->expression);
- g_list_free (vf->priv->folders);
- g_list_free (vf->priv->folders_changed);
-
- camel_folder_change_info_free (vf->changes);
- g_object_unref (vf->search);
+ g_list_free (vf->priv->subfolders);
g_hash_table_foreach (vf->priv->skipped_changes, free_change_info_cb, NULL);
- g_mutex_free (vf->priv->summary_lock);
- g_mutex_free (vf->priv->subfolder_lock);
- g_mutex_free (vf->priv->changed_lock);
- g_hash_table_destroy (vf->hashes);
+ g_static_rec_mutex_free (&vf->priv->summary_lock);
+ g_static_rec_mutex_free (&vf->priv->subfolder_lock);
+ g_static_rec_mutex_free (&vf->priv->changed_lock);
g_hash_table_destroy (vf->priv->ignore_changed);
g_hash_table_destroy (vf->priv->skipped_changes);
+ g_hash_table_destroy (vf->priv->unmatched_add_changed);
+ g_hash_table_destroy (vf->priv->unmatched_remove_changed);
g_async_queue_unref (vf->priv->change_queue);
+ if (vf->priv->vee_data_cache)
+ g_object_unref (vf->priv->vee_data_cache);
+ vf->priv->vee_data_cache = NULL;
+
/* Chain up to parent's finalize () method. */
G_OBJECT_CLASS (camel_vee_folder_parent_class)->finalize (object);
}
static void
+vee_folder_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_AUTO_UPDATE:
+ g_value_set_boolean (
+ value, camel_vee_folder_get_auto_update (
+ CAMEL_VEE_FOLDER (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+vee_folder_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_AUTO_UPDATE:
+ camel_vee_folder_set_auto_update (
+ CAMEL_VEE_FOLDER (object),
+ g_value_get_boolean (value));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
vee_folder_propagate_skipped_changes (CamelVeeFolder *vf)
{
CamelVeeFolderClass *class;
+ CamelFolderChangeInfo *changes = NULL;
GHashTableIter iter;
gpointer psub, pchanges;
@@ -1062,13 +647,47 @@ vee_folder_propagate_skipped_changes (CamelVeeFolder *vf)
camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ /* this is for Unmatched folder only, other folders have unmatched_remove_changed always empty */
+ if (g_hash_table_size (vf->priv->unmatched_add_changed) +
+ g_hash_table_size (vf->priv->unmatched_remove_changed) > 0) {
+ gpointer pkey, pvalue;
+ CamelVeeSummary *vsummary;
+ CamelFolder *v_folder;
+
+ changes = camel_folder_change_info_new ();
+ v_folder = CAMEL_FOLDER (vf);
+ vsummary = CAMEL_VEE_SUMMARY (v_folder->summary);
+
+ /* first remove ... */
+ g_hash_table_iter_init (&iter, vf->priv->unmatched_remove_changed);
+ while (g_hash_table_iter_next (&iter, &pkey, &pvalue)) {
+ CamelVeeMessageInfoData *mi_data = pkey;
+ CamelVeeSubfolderData *sf_data;
+ CamelFolder *subfolder;
+
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ subfolder = camel_vee_subfolder_data_get_folder (sf_data);
+ vee_folder_note_unmatch_uid (vf, vsummary, subfolder, mi_data, changes);
+ }
+ g_hash_table_remove_all (vf->priv->unmatched_remove_changed);
+
+ /* ... then add */
+ g_hash_table_iter_init (&iter, vf->priv->unmatched_add_changed);
+ while (g_hash_table_iter_next (&iter, &pkey, &pvalue)) {
+ CamelVeeMessageInfoData *mi_data = pkey;
+
+ vee_folder_note_added_uid (vf, vsummary, mi_data, changes, FALSE);
+ }
+ g_hash_table_remove_all (vf->priv->unmatched_add_changed);
+ }
+
g_hash_table_iter_init (&iter, vf->priv->skipped_changes);
while (g_hash_table_iter_next (&iter, &psub, &pchanges)) {
g_warn_if_fail (pchanges != NULL);
if (!pchanges)
continue;
- if (g_list_find (vf->priv->folders, psub) != NULL)
+ if (g_list_find (vf->priv->subfolders, psub) != NULL)
class->folder_changed (vf, psub, pchanges);
camel_folder_change_info_free (pchanges);
@@ -1077,6 +696,12 @@ vee_folder_propagate_skipped_changes (CamelVeeFolder *vf)
g_hash_table_remove_all (vf->priv->skipped_changes);
camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+
+ if (changes) {
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (CAMEL_FOLDER (vf), changes);
+ camel_folder_change_info_free (changes);
+ }
}
static GPtrArray *
@@ -1085,59 +710,15 @@ vee_folder_search_by_expression (CamelFolder *folder,
GCancellable *cancellable,
GError **error)
{
- GList *node;
- GPtrArray *matches, *result = g_ptr_array_new ();
- gchar *expr;
- CamelVeeFolder *vf = (CamelVeeFolder *) folder;
- CamelVeeFolderPrivate *p = vf->priv;
- GHashTable *searched = g_hash_table_new (NULL, NULL);
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
- gboolean is_folder_unmatched = vf == folder_unmatched && folder_unmatched;
- CamelFolderSummary *folder_unmatched_summary = NULL;
-
- vee_folder_propagate_skipped_changes (vf);
+ CamelFolderSearch *search;
+ GPtrArray *matches;
- if (is_folder_unmatched) {
- expr = g_strdup (expression);
- folder_unmatched_summary = ((CamelFolder *) folder_unmatched)->summary;
- } else {
- expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression);
- }
+ search = camel_folder_search_new ();
+ camel_folder_search_set_folder (search, folder);
+ matches = camel_folder_search_search (search, expression, NULL, cancellable, error);
+ g_object_unref (search);
- node = p->folders;
- while (node && !g_cancellable_is_cancelled (cancellable)) {
- CamelFolder *f = node->data;
- gint i;
- gchar hash[8];
-
- /* make sure we only search each folder once - for unmatched folder to work right */
- if (g_hash_table_lookup (searched, f) == NULL) {
- camel_vee_folder_hash_folder (f, hash);
- matches = camel_folder_search_by_expression (f, expr, cancellable, NULL);
- if (matches) {
- for (i = 0; i < matches->len; i++) {
- gchar *uid = matches->pdata[i], *vuid;
-
- vuid = g_malloc (strlen (uid) + 9);
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
-
- if (!is_folder_unmatched || camel_folder_summary_check_uid (folder_unmatched_summary, vuid))
- g_ptr_array_add (result, (gpointer) camel_pstring_strdup (vuid));
- g_free (vuid);
- }
- camel_folder_search_free (f, matches);
- }
- g_hash_table_insert (searched, f, f);
- }
- node = g_list_next (node);
- }
-
- g_free (expr);
-
- g_hash_table_destroy (searched);
- d (printf ("returning %d\n", result->len));
- return result;
+ return matches;
}
static GPtrArray *
@@ -1147,64 +728,18 @@ vee_folder_search_by_uids (CamelFolder *folder,
GCancellable *cancellable,
GError **error)
{
- GList *node;
- GPtrArray *matches, *result = g_ptr_array_new ();
- GPtrArray *folder_uids = g_ptr_array_new ();
- gchar *expr;
- CamelVeeFolder *vf = (CamelVeeFolder *) folder;
- CamelVeeFolderPrivate *p = vf->priv;
- GHashTable *searched = g_hash_table_new (NULL, NULL);
-
- vee_folder_propagate_skipped_changes (vf);
-
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ CamelFolderSearch *search;
+ GPtrArray *matches;
- expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression);
- node = p->folders;
- while (node && !g_cancellable_is_cancelled (cancellable)) {
- CamelFolder *f = node->data;
- gint i;
- gchar hash[8];
+ if (!uids || uids->len == 0)
+ return g_ptr_array_new ();
- /* make sure we only search each folder once - for unmatched folder to work right */
- if (g_hash_table_lookup (searched, f) == NULL) {
- camel_vee_folder_hash_folder (f, hash);
+ search = camel_folder_search_new ();
+ camel_folder_search_set_folder (search, folder);
+ matches = camel_folder_search_search (search, expression, uids, cancellable, error);
+ g_object_unref (search);
- /* map the vfolder uid's to the source folder uid's first */
- g_ptr_array_set_size (folder_uids, 0);
- for (i = 0; i < uids->len; i++) {
- gchar *uid = uids->pdata[i];
-
- if (strlen (uid) >= 8 && strncmp (uid, hash, 8) == 0)
- g_ptr_array_add (folder_uids, uid + 8);
- }
- if (folder_uids->len > 0) {
- matches = camel_folder_search_by_uids (f, expr, folder_uids, cancellable, error);
- if (matches) {
- for (i = 0; i < matches->len; i++) {
- gchar *uid = matches->pdata[i], *vuid;
-
- vuid = g_malloc (strlen (uid) + 9);
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
- g_ptr_array_add (result, (gpointer) camel_pstring_strdup (vuid));
- g_free (vuid);
- }
- camel_folder_search_free (f, matches);
- }
- }
- g_hash_table_insert (searched, f, f);
- }
- node = g_list_next (node);
- }
-
- g_free (expr);
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-
- g_hash_table_destroy (searched);
- g_ptr_array_free (folder_uids, TRUE);
-
- return result;
+ return matches;
}
static guint32
@@ -1213,82 +748,64 @@ vee_folder_count_by_expression (CamelFolder *folder,
GCancellable *cancellable,
GError **error)
{
- GList *node;
- gchar *expr;
- guint32 count = 0;
- CamelVeeFolder *vf = (CamelVeeFolder *) folder;
- CamelVeeFolderPrivate *p = vf->priv;
- GHashTable *searched = g_hash_table_new (NULL, NULL);
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
-
- vee_folder_propagate_skipped_changes (vf);
-
- if (vf != folder_unmatched)
- expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression);
- else
- expr = g_strdup (expression);
+ CamelFolderSearch *search;
+ guint32 count;
- node = p->folders;
- while (node && !g_cancellable_is_cancelled (cancellable)) {
- CamelFolder *f = node->data;
+ search = camel_folder_search_new ();
+ camel_folder_search_set_folder (search, folder);
+ count = camel_folder_search_count (search, expression, cancellable, error);
+ g_object_unref (search);
- /* make sure we only search each folder once - for unmatched folder to work right */
- if (g_hash_table_lookup (searched, f) == NULL) {
- count += camel_folder_count_by_expression (f, expr, cancellable, NULL);
- g_hash_table_insert (searched, f, f);
- }
- node = g_list_next (node);
- }
-
- g_free (expr);
-
- g_hash_table_destroy (searched);
return count;
}
static void
+vee_folder_search_free (CamelFolder *folder,
+ GPtrArray *result)
+{
+ camel_folder_search_free_result (NULL, result);
+}
+
+static void
vee_folder_delete (CamelFolder *folder)
{
- CamelVeeFolderPrivate *p = CAMEL_VEE_FOLDER_GET_PRIVATE (folder);
+ CamelVeeFolder *vfolder;
+
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (folder));
- /* NB: this is never called on UNMTACHED */
+ vfolder = CAMEL_VEE_FOLDER (folder);
- camel_vee_folder_lock (CAMEL_VEE_FOLDER (folder), CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- while (p->folders) {
- CamelFolder *f = p->folders->data;
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ while (vfolder->priv->subfolders) {
+ CamelFolder *subfolder = vfolder->priv->subfolders->data;
+
+ g_object_ref (subfolder);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- g_object_ref (f);
- camel_vee_folder_unlock (CAMEL_VEE_FOLDER (folder), CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ camel_vee_folder_remove_folder (vfolder, subfolder, NULL);
+ g_object_unref (subfolder);
- camel_vee_folder_remove_folder ((CamelVeeFolder *) folder, f);
- g_object_unref (f);
- camel_vee_folder_lock (CAMEL_VEE_FOLDER (folder), CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
}
- camel_vee_folder_unlock (CAMEL_VEE_FOLDER (folder), CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
((CamelFolderClass *) camel_vee_folder_parent_class)->delete (folder);
- ((CamelVeeFolder *) folder)->deleted = TRUE;
}
static void
vee_folder_freeze (CamelFolder *folder)
{
- CamelVeeFolder *vfolder = (CamelVeeFolder *) folder;
- CamelVeeFolderPrivate *p = vfolder->priv;
- GList *node;
+ CamelVeeFolder *vfolder = CAMEL_VEE_FOLDER (folder);
- camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ if (vfolder->priv->parent_vee_store &&
+ !vee_folder_is_unmatched (vfolder)) {
+ CamelVeeFolder *unmatched_folder;
- node = p->folders;
- while (node) {
- CamelFolder *f = node->data;
-
- camel_folder_freeze (f);
- node = node->next;
+ unmatched_folder = camel_vee_store_get_unmatched_folder (vfolder->priv->parent_vee_store);
+ if (unmatched_folder)
+ camel_folder_freeze (CAMEL_FOLDER (unmatched_folder));
}
- camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-
/* call parent implementation */
CAMEL_FOLDER_CLASS (camel_vee_folder_parent_class)->freeze (folder);
}
@@ -1296,21 +813,16 @@ vee_folder_freeze (CamelFolder *folder)
static void
vee_folder_thaw (CamelFolder *folder)
{
- CamelVeeFolder *vfolder = (CamelVeeFolder *) folder;
- CamelVeeFolderPrivate *p = vfolder->priv;
- GList *node;
+ CamelVeeFolder *vfolder = CAMEL_VEE_FOLDER (folder);
- camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ if (vfolder->priv->parent_vee_store &&
+ !vee_folder_is_unmatched (vfolder)) {
+ CamelVeeFolder *unmatched_folder;
- node = p->folders;
- while (node) {
- CamelFolder *f = node->data;
-
- camel_folder_thaw (f);
- node = node->next;
- }
-
- camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ unmatched_folder = camel_vee_store_get_unmatched_folder (vfolder->priv->parent_vee_store);
+ if (unmatched_folder)
+ camel_folder_thaw (CAMEL_FOLDER (unmatched_folder));
+ }
/* call parent implementation */
CAMEL_FOLDER_CLASS (camel_vee_folder_parent_class)->thaw (folder);
@@ -1372,32 +884,11 @@ vee_folder_refresh_info_sync (CamelFolder *folder,
GError **error)
{
CamelVeeFolder *vf = (CamelVeeFolder *) folder;
- CamelVeeFolderPrivate *p = vf->priv;
- GList *node, *list;
- gboolean success = TRUE;
vee_folder_propagate_skipped_changes (vf);
+ vee_folder_rebuild_all (vf, cancellable);
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- list = p->folders_changed;
- p->folders_changed = NULL;
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
-
- node = list;
- while (node) {
- CamelFolder *f = node->data;
-
- if (camel_vee_folder_rebuild_folder (vf, f, error) == -1) {
- success = FALSE;
- break;
- }
-
- node = node->next;
- }
-
- g_list_free (list);
-
- return success;
+ return TRUE;
}
static gboolean
@@ -1406,70 +897,44 @@ vee_folder_synchronize_sync (CamelFolder *folder,
GCancellable *cancellable,
GError **error)
{
- CamelVeeFolder *vf = (CamelVeeFolder *) folder;
- CamelVeeFolderPrivate *p = vf->priv;
- GList *node;
+ CamelVeeFolder *vfolder = (CamelVeeFolder *) folder;
+ gboolean res = TRUE;
+ GList *iter;
- vee_folder_propagate_skipped_changes (vf);
+ g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (folder), FALSE);
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ vee_folder_propagate_skipped_changes (vfolder);
- node = p->folders;
- while (node) {
+ /* basically no-op here, especially do not call synchronize on subfolders
+ if not expunging, they are responsible for themselfs */
+ if (!expunge ||
+ vee_folder_is_unmatched (vfolder))
+ return TRUE;
+
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+
+ for (iter = vfolder->priv->subfolders; iter && !g_cancellable_is_cancelled (cancellable); iter = iter->next) {
GError *local_error = NULL;
- CamelFolder *f = node->data;
+ CamelFolder *subfolder = iter->data;
- if (!camel_folder_synchronize_sync (f, expunge, cancellable, &local_error)) {
+ if (!camel_folder_synchronize_sync (subfolder, expunge, cancellable, &local_error)) {
if (local_error && strncmp (local_error->message, "no such table", 13) != 0 && error && !*error) {
const gchar *desc;
- desc = camel_folder_get_description (f);
- g_warning ("%s", local_error->message);
+ desc = camel_folder_get_description (subfolder);
g_propagate_prefixed_error (
error, local_error,
_("Error storing '%s': "), desc);
+
+ res = FALSE;
} else
g_clear_error (&local_error);
}
-
- /* auto update vfolders shouldn't need a rebuild */
-/* if ((vf->flags & CAMEL_STORE_VEE_FOLDER_AUTO) == 0 */
-/* && camel_vee_folder_rebuild_folder (vf, f, ex) == -1) */
-/* break; */
-
- node = node->next;
}
- if (!CAMEL_IS_VTRASH_FOLDER (vf)) {
- /* Cleanup Junk/Trash uids */
- CamelStore *parent_store;
- const gchar *full_name;
- GList *del = NULL;
- gint i;
- GPtrArray *known_uids;
-
- camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
- known_uids = camel_folder_summary_get_array (folder->summary);
- for (i = 0; known_uids && i < known_uids->len; i++) {
- CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, g_ptr_array_index (known_uids, i));
- if (mi->old_flags & CAMEL_MESSAGE_DELETED) {
- del = g_list_prepend (del, (gpointer) camel_pstring_strdup (((CamelMessageInfo *) mi)->uid));
- camel_folder_summary_remove_uid (folder->summary, ((CamelMessageInfo *) mi)->uid);
-
- }
- camel_message_info_free (mi);
- }
- camel_folder_summary_free_array (known_uids);
-
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
- camel_db_delete_vuids (parent_store->cdb_w, full_name, "", del, NULL);
- g_list_foreach (del, (GFunc) camel_pstring_free, NULL);
- g_list_free (del);
- }
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- return TRUE;
+ return res;
}
static gboolean
@@ -1492,489 +957,124 @@ static void
vee_folder_set_expression (CamelVeeFolder *vee_folder,
const gchar *query)
{
- CamelVeeFolderPrivate *p = CAMEL_VEE_FOLDER_GET_PRIVATE (vee_folder);
- GList *node;
-
camel_vee_folder_lock (vee_folder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
/* no change, do nothing */
- if ((vee_folder->expression && query && strcmp (vee_folder->expression, query) == 0)
- || (vee_folder->expression == NULL && query == NULL)) {
+ if ((vee_folder->priv->expression && query && strcmp (vee_folder->priv->expression, query) == 0)
+ || (vee_folder->priv->expression == NULL && query == NULL)) {
camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
return;
}
- /* Recreate the table when the query changes, only if we are not setting it first */
- if (vee_folder->expression) {
- CamelFolderSummary *summary;
- CamelStore *parent_store;
- CamelFolder *folder;
- const gchar *full_name;
-
- folder = CAMEL_FOLDER (vee_folder);
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
- summary = folder->summary;
-
- camel_folder_summary_clear (summary, NULL);
- camel_db_recreate_vfolder (parent_store->cdb_w, full_name, NULL);
- }
-
- g_free (vee_folder->expression);
+ g_free (vee_folder->priv->expression);
if (query)
- vee_folder->expression = g_strdup (query);
-
- node = p->folders;
- while (node) {
- CamelFolder *f = node->data;
-
- if (camel_vee_folder_rebuild_folder (vee_folder, f, NULL) == -1)
- break;
-
- node = node->next;
- }
+ vee_folder->priv->expression = g_strdup (query);
- camel_vee_folder_lock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- g_list_free (p->folders_changed);
- p->folders_changed = NULL;
- camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ vee_folder_rebuild_all (vee_folder, NULL);
camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
}
static void
-vee_folder_add_folder (CamelVeeFolder *vee_folder,
- CamelFolder *sub)
+vee_folder_rebuild_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable)
{
- vee_folder_rebuild_folder (vee_folder, sub, NULL);
-}
-
-static void
-vee_folder_remove_folder_helper (CamelVeeFolder *vf,
- CamelFolder *source)
-{
- gint i, n, still = FALSE;
- gchar *oldkey;
- CamelFolder *folder = (CamelFolder *) vf;
- gchar hash[8];
- CamelFolderChangeInfo *vf_changes = NULL, *unmatched_changes = NULL;
- gpointer oldval;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
- GHashTable *unmatched_uids = vf->parent_vee_store ? vf->parent_vee_store->unmatched_uids : NULL;
- CamelFolderSummary *ssummary = source->summary;
- gint killun = FALSE;
- GPtrArray *known_uids;
-
- if (vf == folder_unmatched)
- return;
-
- if ((source->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED))
- killun = TRUE;
-
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
-
- if (folder_unmatched != NULL) {
- /* check if this folder is still to be part of unmatched */
- if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !killun) {
- camel_vee_folder_lock (folder_unmatched, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- still = g_list_find (CAMEL_VEE_FOLDER_GET_PRIVATE (folder_unmatched)->folders, source) != NULL;
- camel_vee_folder_unlock (folder_unmatched, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- camel_vee_folder_hash_folder (source, hash);
- }
-
- camel_vee_folder_lock (folder_unmatched, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
-
- /* See if we just blow all uid's from this folder away from unmatched, regardless */
- if (killun) {
- camel_folder_summary_prepare_fetch_all (((CamelFolder *) folder_unmatched)->summary, NULL);
- known_uids = camel_folder_summary_get_array (((CamelFolder *) folder_unmatched)->summary);
- for (i = 0; known_uids && i < known_uids->len; i++) {
- CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *)
- camel_folder_summary_get (((CamelFolder *) folder_unmatched)->summary, g_ptr_array_index (known_uids, i));
-
- if (mi) {
- if (mi->orig_summary == ssummary) {
- camel_folder_change_info_remove_uid (folder_unmatched->changes, camel_message_info_uid (mi));
- camel_folder_summary_remove_uid (((CamelFolder *) folder_unmatched)->summary, camel_message_info_uid (mi));
- }
- camel_message_info_free ((CamelMessageInfo *) mi);
- }
- }
- camel_folder_summary_free_array (known_uids);
- }
- }
-
- /*FIXME: This can be optimized a lot like, searching for UID in the summary uids */
- camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
- known_uids = camel_folder_summary_get_array (folder->summary);
- for (i = 0; known_uids && i < known_uids->len; i++) {
- CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, g_ptr_array_index (known_uids, i));
- if (mi) {
- if (mi->orig_summary == ssummary) {
- const gchar *uid = camel_message_info_uid (mi);
-
- camel_folder_change_info_remove_uid (vf->changes, uid);
- camel_folder_summary_remove_uid (folder->summary, uid);
-
- if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && folder_unmatched != NULL) {
- if (still) {
- if (g_hash_table_lookup_extended (unmatched_uids, uid, (gpointer *) &oldkey, &oldval)) {
- n = GPOINTER_TO_INT (oldval);
- if (n == 1) {
- g_hash_table_remove (unmatched_uids, oldkey);
- if (vee_folder_add_uid_test (folder_unmatched, source, oldkey + 8, hash)) {
- camel_folder_change_info_add_uid (folder_unmatched->changes, oldkey);
- }
- g_free (oldkey);
- } else {
- g_hash_table_insert (unmatched_uids, oldkey, GINT_TO_POINTER (n - 1));
- }
- }
- } else {
- if (g_hash_table_lookup_extended (unmatched_uids, camel_message_info_uid (mi), (gpointer *) &oldkey, &oldval)) {
- g_hash_table_remove (unmatched_uids, oldkey);
- g_free (oldkey);
- }
- }
- }
- }
- camel_message_info_free ((CamelMessageInfo *) mi);
- }
- }
- camel_folder_summary_free_array (known_uids);
-
- if (folder_unmatched) {
- if (camel_folder_change_info_changed (folder_unmatched->changes)) {
- unmatched_changes = folder_unmatched->changes;
- folder_unmatched->changes = camel_folder_change_info_new ();
- }
-
- camel_vee_folder_unlock (folder_unmatched, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
- }
-
- if (camel_folder_change_info_changed (vf->changes)) {
- vf_changes = vf->changes;
- vf->changes = camel_folder_change_info_new ();
- }
+ CamelFolderChangeInfo *changes;
+ CamelFolder *v_folder;
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
+ v_folder = CAMEL_FOLDER (vfolder);
+ changes = camel_folder_change_info_new ();
- if (unmatched_changes) {
- camel_folder_changed (
- CAMEL_FOLDER (folder_unmatched), unmatched_changes);
- camel_folder_change_info_free (unmatched_changes);
- }
+ camel_folder_freeze (v_folder);
+ vee_folder_rebuild_folder_with_changes (vfolder, subfolder, changes, cancellable);
+ camel_folder_thaw (v_folder);
- if (vf_changes) {
- camel_folder_changed (CAMEL_FOLDER (vf), vf_changes);
- camel_folder_change_info_free (vf_changes);
- }
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (CAMEL_FOLDER (vfolder), changes);
+ camel_folder_change_info_free (changes);
}
static void
-vee_folder_remove_folder (CamelVeeFolder *vee_folder,
- CamelFolder *sub)
+vee_folder_add_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable)
{
- gchar *shash, hash[8];
- CamelVeeFolder *folder_unmatched = vee_folder->parent_vee_store ? vee_folder->parent_vee_store->folder_unmatched : NULL;
-
- camel_vee_folder_hash_folder (sub, hash);
- vee_folder_remove_folder_helper (vee_folder, sub);
- shash = g_strdup_printf (
- "%c%c%c%c%c%c%c%c",
- hash[0], hash[1], hash[2], hash[3],
- hash[4], hash[5], hash[6], hash[7]);
- if (g_hash_table_lookup (vee_folder->hashes, shash)) {
- g_hash_table_remove (vee_folder->hashes, shash);
- }
-
- if (folder_unmatched && g_hash_table_lookup (folder_unmatched->hashes, shash)) {
- g_hash_table_remove (folder_unmatched->hashes, shash);
- }
-
- g_free (shash);
+ if (vfolder->priv->parent_vee_store)
+ camel_vee_store_note_subfolder_used (vfolder->priv->parent_vee_store, subfolder, vfolder);
+ vee_folder_rebuild_folder (vfolder, subfolder, cancellable);
}
-static gint
-vee_folder_rebuild_folder (CamelVeeFolder *vee_folder,
- CamelFolder *source,
- GError **error)
+static gboolean
+vee_folder_remove_from_unmatched_changed_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
{
- GPtrArray *match = NULL, *all;
- GHashTable *allhash, *matchhash, *fullhash;
- GList *del_list = NULL;
- CamelFolder *folder = (CamelFolder *) vee_folder;
- gint i, n, count;
- struct _update_data u;
- CamelFolderChangeInfo *vee_folder_changes = NULL, *unmatched_changes = NULL;
- CamelVeeFolder *folder_unmatched = vee_folder->parent_vee_store ? vee_folder->parent_vee_store->folder_unmatched : NULL;
- GHashTable *unmatched_uids = vee_folder->parent_vee_store ? vee_folder->parent_vee_store->unmatched_uids : NULL;
- CamelFolderSummary *ssummary = source->summary;
- gboolean rebuilded = FALSE;
- gchar *shash;
- GPtrArray *known_uids;
-
- /* Since the source of a correlating vfolder has to be requeried in
- * full every time it changes, caching the results in the db is not
- * worth the effort. Thus, DB use is conditioned on !correlating. */
- gboolean correlating = vee_folder->expression && expression_is_correlating (vee_folder->expression);
-
- if (vee_folder == folder_unmatched)
- return 0;
-
- camel_vee_folder_hash_folder (source, u.hash);
- shash = g_strdup_printf ("%c%c%c%c%c%c%c%c", u.hash[0], u.hash[1], u.hash[2], u.hash[3], u.hash[4], u.hash[5], u.hash[6], u.hash[7]);
- if (!g_hash_table_lookup (vee_folder->hashes, shash)) {
- g_hash_table_insert (vee_folder->hashes, g_strdup (shash), source->summary);
- }
- if (folder_unmatched && !g_hash_table_lookup (folder_unmatched->hashes, shash)) {
- g_hash_table_insert (folder_unmatched->hashes, g_strdup (shash), source->summary);
- }
-
- /* if we have no expression, or its been cleared, then act as if no matches */
- if (vee_folder->expression == NULL) {
- match = g_ptr_array_new ();
- } else {
- if (!correlating) {
- /* Load the folder results from the DB. */
- match = camel_vee_summary_get_ids ((CamelVeeSummary *) folder->summary, u.hash);
- }
- if (correlating ||
- /* We take this to mean the results have not been cached.
- * XXX: It will also trigger if the result set is empty. */
- match == NULL) {
- match = camel_folder_search_by_expression (source, vee_folder->expression, NULL, error);
- if (match == NULL) /* Search failed */
- return 0;
- rebuilded = TRUE;
- }
-
- }
-
- u.source = source;
- u.vee_folder = vee_folder;
- u.folder_unmatched = folder_unmatched;
- u.unmatched_uids = unmatched_uids;
- u.rebuilt = rebuilded;
- u.correlating = correlating;
-
- camel_vee_folder_lock (vee_folder, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
-
- /* we build 2 hash tables, one for all uid's not matched, the
- * other for all matched uid's, we just ref the real memory */
- matchhash = g_hash_table_new (g_str_hash, g_str_equal);
- for (i = 0; i < match->len; i++)
- g_hash_table_insert (matchhash, match->pdata[i], GINT_TO_POINTER (1));
-
- allhash = g_hash_table_new (g_str_hash, g_str_equal);
- fullhash = g_hash_table_new (g_str_hash, g_str_equal);
- all = camel_folder_summary_get_array (source->summary);
- for (i = 0; i < all->len; i++) {
- if (g_hash_table_lookup (matchhash, all->pdata[i]) == NULL)
- g_hash_table_insert (allhash, all->pdata[i], GINT_TO_POINTER (1));
- g_hash_table_insert (fullhash, all->pdata[i], GINT_TO_POINTER (1));
-
- }
- /* remove uids that can't be found in the source folder */
- count = match->len;
- for (i = 0; i < count; i++) {
- if (!g_hash_table_lookup (fullhash, match->pdata[i])) {
- g_hash_table_remove (matchhash, match->pdata[i]);
- del_list = g_list_prepend (del_list, match->pdata[i]); /* Free the original */
- g_ptr_array_remove_index_fast (match, i);
- i--;
- count--;
- continue;
- }
- }
-
- if (folder_unmatched != NULL)
- camel_vee_folder_lock (folder_unmatched, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
-
- /* scan, looking for "old" uid's to be removed. "old" uid's
- * are those that are from previous added sources (not in
- * current source) */
- camel_folder_summary_prepare_fetch_all (folder->summary, NULL);
- known_uids = camel_folder_summary_get_array (folder->summary);
- for (i = 0; known_uids && i < known_uids->len; i++) {
- CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) camel_folder_summary_get (folder->summary, g_ptr_array_index (known_uids, i));
-
- if (mi) {
- if (mi->orig_summary == ssummary) {
- gchar *uid = (gchar *) camel_message_info_uid (mi), *oldkey;
- gpointer oldval;
-
- if (g_hash_table_lookup (matchhash, uid + 8) == NULL) {
- camel_folder_change_info_remove_uid (vee_folder->changes, camel_message_info_uid (mi));
- camel_folder_summary_remove_uid (folder->summary, uid);
-
- if (!CAMEL_IS_VEE_FOLDER (source)
- && unmatched_uids != NULL
- && g_hash_table_lookup_extended (unmatched_uids, uid, (gpointer *) &oldkey, &oldval)) {
- n = GPOINTER_TO_INT (oldval);
- if (n == 1) {
- g_hash_table_remove (unmatched_uids, oldkey);
- g_free (oldkey);
- } else {
- g_hash_table_insert (unmatched_uids, oldkey, GINT_TO_POINTER (n - 1));
- }
- }
- } else {
- g_hash_table_remove (matchhash, uid + 8);
- }
- }
- camel_message_info_free ((CamelMessageInfo *) mi);
- }
- }
- camel_folder_summary_free_array (known_uids);
+ CamelVeeMessageInfoData *mi_data = key;
+ CamelFolder *subfolder = user_data;
+ CamelVeeSubfolderData *sf_data;
- if (rebuilded && !correlating)
- u.message_uids = g_queue_new ();
- else
- u.message_uids = NULL;
-
- /* now matchhash contains any new uid's, add them, etc */
- g_hash_table_foreach (matchhash, (GHFunc) folder_added_uid, &u);
-
- if (u.message_uids != NULL) {
- CamelStore *parent_store;
- const gchar *full_name;
- gchar *uid;
-
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
-
- camel_db_begin_transaction (parent_store->cdb_w, NULL);
-
- while ((uid = g_queue_pop_head (u.message_uids)) != NULL) {
- camel_db_add_to_vfolder_transaction (
- parent_store->cdb_w, full_name, uid, NULL);
- g_free (uid);
- }
-
- camel_db_end_transaction (parent_store->cdb_w, NULL);
-
- g_queue_free (u.message_uids);
- u.message_uids = NULL;
- }
-
- if (folder_unmatched != NULL) {
- /* scan unmatched, remove any that have vanished, etc */
- GPtrArray *known_uids;
-
- known_uids = camel_folder_summary_get_array (((CamelFolder *) folder_unmatched)->summary);
- if (known_uids != NULL) {
- for (i = 0; i < known_uids->len; i++) {
- const gchar *uid = g_ptr_array_index (known_uids, i);
-
- if (uid) {
- if (strncmp (uid, u.hash, 8) == 0) {
- if (g_hash_table_lookup (allhash, uid + 8) == NULL) {
- /* no longer exists at all, just remove it entirely */
- camel_folder_summary_remove_uid (((CamelFolder *) folder_unmatched)->summary, uid);
- camel_folder_change_info_remove_uid (folder_unmatched->changes, uid);
- } else {
- g_hash_table_remove (allhash, uid + 8);
- }
- }
- }
- }
- camel_folder_summary_free_array (known_uids);
- }
-
- /* now allhash contains all potentially new uid's for the unmatched folder, process */
- if (!CAMEL_IS_VEE_FOLDER (source)) {
-
- u.message_uids = g_queue_new ();
- g_hash_table_foreach (allhash, (GHFunc) unmatched_check_uid, &u);
+ g_return_val_if_fail (mi_data != NULL, TRUE);
- if (!g_queue_is_empty (u.message_uids)) {
- CamelStore *parent_store;
- const gchar *full_name;
- gchar *uid;
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
- full_name = camel_folder_get_full_name (CAMEL_FOLDER (u.folder_unmatched));
- parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (u.folder_unmatched));
-
- camel_db_begin_transaction (parent_store->cdb_w, NULL);
-
- while ((uid = g_queue_pop_head (u.message_uids)) != NULL) {
- camel_db_add_to_vfolder_transaction (
- parent_store->cdb_w, full_name, uid, NULL);
- g_free (uid);
- }
-
- camel_db_end_transaction (parent_store->cdb_w, NULL);
- }
-
- g_queue_free (u.message_uids);
- u.message_uids = NULL;
- }
+ return subfolder == camel_vee_subfolder_data_get_folder (sf_data);
+}
- /* copy any changes so we can raise them outside the lock */
- if (camel_folder_change_info_changed (folder_unmatched->changes)) {
- unmatched_changes = folder_unmatched->changes;
- folder_unmatched->changes = camel_folder_change_info_new ();
+static void
+vee_folder_remove_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable)
+{
+ CamelFolderChangeInfo *changes;
+ CamelFolder *v_folder;
+ GHashTable *uids;
+
+ v_folder = CAMEL_FOLDER (vfolder);
+ changes = camel_folder_change_info_new ();
+
+ camel_folder_freeze (v_folder);
+
+ uids = camel_vee_summary_get_uids_for_subfolder (CAMEL_VEE_SUMMARY (v_folder->summary), subfolder);
+ if (uids) {
+ struct RemoveUnmatchedData rud;
+
+ rud.vfolder = vfolder;
+ rud.vsummary = CAMEL_VEE_SUMMARY (v_folder->summary);
+ rud.subfolder = subfolder;
+ rud.data_cache = vee_folder_get_data_cache (vfolder);
+ rud.changes = changes;
+ rud.is_orig_message_uid = FALSE;
+
+ g_hash_table_foreach (uids, vee_folder_remove_unmatched_cb, &rud);
+
+ if (vee_folder_is_unmatched (vfolder) &&
+ !camel_vee_folder_get_auto_update (vfolder) &&
+ g_hash_table_size (vfolder->priv->unmatched_add_changed) +
+ g_hash_table_size (vfolder->priv->unmatched_remove_changed) > 0) {
+ /* forget about these in cached updates */
+ g_hash_table_foreach_remove (vfolder->priv->unmatched_add_changed,
+ vee_folder_remove_from_unmatched_changed_cb, subfolder);
+ g_hash_table_foreach_remove (vfolder->priv->unmatched_remove_changed,
+ vee_folder_remove_from_unmatched_changed_cb, subfolder);
}
- camel_vee_folder_unlock (folder_unmatched, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
- }
-
- if (camel_folder_change_info_changed (vee_folder->changes)) {
- vee_folder_changes = vee_folder->changes;
- vee_folder->changes = camel_folder_change_info_new ();
+ g_hash_table_destroy (uids);
}
- camel_vee_folder_unlock (vee_folder, CAMEL_VEE_FOLDER_SUMMARY_LOCK);
-
- /* Del the unwanted things from the summary, we don't hold any locks now. */
- if (del_list) {
- if (!correlating) {
- CamelStore *parent_store;
- const gchar *full_name;
-
- full_name = camel_folder_get_full_name (folder);
- parent_store = camel_folder_get_parent_store (folder);
- camel_db_delete_vuids (
- parent_store->cdb_w,
- full_name, shash, del_list, NULL);
- }
-
- g_list_foreach (del_list, (GFunc) camel_pstring_free, NULL);
- g_list_free (del_list);
- };
-
- g_hash_table_destroy (matchhash);
- g_hash_table_destroy (allhash);
- g_hash_table_destroy (fullhash);
-
- g_free (shash);
- /* if expression not set, we only had a null list */
- if (vee_folder->expression == NULL || !rebuilded) {
- g_ptr_array_foreach (match, (GFunc) camel_pstring_free, NULL);
- g_ptr_array_free (match, TRUE);
- } else
- camel_folder_search_free (source, match);
- camel_folder_summary_free_array (all);
-
- if (unmatched_changes) {
- camel_folder_changed (
- CAMEL_FOLDER (folder_unmatched), unmatched_changes);
- camel_folder_change_info_free (unmatched_changes);
- }
+ if (vfolder->priv->parent_vee_store)
+ camel_vee_store_note_subfolder_unused (vfolder->priv->parent_vee_store, subfolder, vfolder);
- if (vee_folder_changes) {
- camel_folder_changed (
- CAMEL_FOLDER (vee_folder), vee_folder_changes);
- camel_folder_change_info_free (vee_folder_changes);
- }
+ camel_folder_thaw (v_folder);
- return 0;
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (CAMEL_FOLDER (vfolder), changes);
+ camel_folder_change_info_free (changes);
}
static void
vee_folder_folder_changed (CamelVeeFolder *vee_folder,
- CamelFolder *sub,
+ CamelFolder *subfolder,
CamelFolderChangeInfo *changes)
{
CamelVeeFolderPrivate *p = vee_folder->priv;
@@ -1992,10 +1092,7 @@ vee_folder_folder_changed (CamelVeeFolder *vee_folder,
g_async_queue_lock (vee_folder->priv->change_queue);
- data = g_slice_new0 (FolderChangedData);
- data->changes = camel_folder_change_info_new ();
- camel_folder_change_info_cat (data->changes, changes);
- data->sub = g_object_ref (sub);
+ data = vee_folder_changed_data_new (subfolder, changes);
g_async_queue_push_unlocked (vee_folder->priv->change_queue, data);
@@ -2012,26 +1109,6 @@ vee_folder_folder_changed (CamelVeeFolder *vee_folder,
}
static void
-vee_folder_folder_renamed (CamelVeeFolder *vee_folder,
- CamelFolder *f,
- const gchar *old)
-{
- gchar hash[8];
- CamelVeeFolder *folder_unmatched = vee_folder->parent_vee_store ? vee_folder->parent_vee_store->folder_unmatched : NULL;
-
- /* TODO: This could probably be done in another thread, tho it is pretty quick/memory bound */
-
- /* Life just got that little bit harder, if the folder is renamed, it means it breaks all of our uid's.
- * We need to remove the old uid's, fix them up, then release the new uid's, for the uid's that match this folder */
-
- camel_vee_folder_hash_folder (f, hash);
-
- subfolder_renamed_update (vee_folder, f, hash);
- if (folder_unmatched != NULL)
- subfolder_renamed_update (folder_unmatched, f, hash);
-}
-
-static void
camel_vee_folder_class_init (CamelVeeFolderClass *class)
{
GObjectClass *object_class;
@@ -2042,11 +1119,14 @@ camel_vee_folder_class_init (CamelVeeFolderClass *class)
object_class = G_OBJECT_CLASS (class);
object_class->dispose = vee_folder_dispose;
object_class->finalize = vee_folder_finalize;
+ object_class->get_property = vee_folder_get_property;
+ object_class->set_property = vee_folder_set_property;
folder_class = CAMEL_FOLDER_CLASS (class);
folder_class->search_by_expression = vee_folder_search_by_expression;
folder_class->search_by_uids = vee_folder_search_by_uids;
folder_class->count_by_expression = vee_folder_count_by_expression;
+ folder_class->search_free = vee_folder_search_free;
folder_class->delete = vee_folder_delete;
folder_class->freeze = vee_folder_freeze;
folder_class->thaw = vee_folder_thaw;
@@ -2062,7 +1142,17 @@ camel_vee_folder_class_init (CamelVeeFolderClass *class)
class->remove_folder = vee_folder_remove_folder;
class->rebuild_folder = vee_folder_rebuild_folder;
class->folder_changed = vee_folder_folder_changed;
- class->folder_renamed = vee_folder_folder_renamed;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_AUTO_UPDATE,
+ g_param_spec_boolean (
+ "auto-update",
+ "Auto Update",
+ _("Automatically _update on change in source folders"),
+ TRUE,
+ G_PARAM_READWRITE |
+ CAMEL_PARAM_PERSISTENT));
}
static void
@@ -2081,22 +1171,20 @@ camel_vee_folder_init (CamelVeeFolder *vee_folder)
CAMEL_MESSAGE_FLAGGED |
CAMEL_MESSAGE_SEEN;
- vee_folder->changes = camel_folder_change_info_new ();
- vee_folder->search = camel_folder_search_new ();
- vee_folder->hashes = g_hash_table_new_full (
- g_str_hash, g_str_equal, g_free, NULL);
-
- /* Loaded is no longer used.*/
- vee_folder->loaded = NULL;
- vee_folder->deleted = FALSE;
- vee_folder->priv->summary_lock = g_mutex_new ();
- vee_folder->priv->subfolder_lock = g_mutex_new ();
- vee_folder->priv->changed_lock = g_mutex_new ();
+ g_static_rec_mutex_init (&vee_folder->priv->summary_lock);
+ g_static_rec_mutex_init (&vee_folder->priv->subfolder_lock);
+ g_static_rec_mutex_init (&vee_folder->priv->changed_lock);
+
+ vee_folder->priv->auto_update = TRUE;
vee_folder->priv->ignore_changed = g_hash_table_new (g_direct_hash, g_direct_equal);
vee_folder->priv->skipped_changes = g_hash_table_new (g_direct_hash, g_direct_equal);
+ vee_folder->priv->unmatched_add_changed =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
+ vee_folder->priv->unmatched_remove_changed =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal, g_object_unref, NULL);
vee_folder->priv->change_queue = g_async_queue_new_full (
- (GDestroyNotify) folder_changed_data_free);
+ (GDestroyNotify) vee_folder_changed_data_free);
}
void
@@ -2108,12 +1196,34 @@ camel_vee_folder_construct (CamelVeeFolder *vf,
vf->flags = flags;
+ parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (vf));
+ if (CAMEL_IS_VEE_STORE (parent_store))
+ vf->priv->parent_vee_store = CAMEL_VEE_STORE (parent_store);
+ else
+ vf->priv->vee_data_cache = camel_vee_data_cache_new ();
+
folder->summary = camel_vee_summary_new (folder);
- parent_store = camel_folder_get_parent_store (CAMEL_FOLDER (vf));
+ /* only for subfolders of vee-store */
+ if (vf->priv->parent_vee_store) {
+ const gchar *user_data_dir;
+ gchar *state_file, *folder_name, *filename;
- if (CAMEL_IS_VEE_STORE (parent_store))
- vf->parent_vee_store = CAMEL_VEE_STORE (parent_store);
+ user_data_dir = camel_service_get_user_data_dir (CAMEL_SERVICE (parent_store));
+
+ folder_name = g_uri_escape_string (camel_folder_get_full_name (folder), NULL, TRUE);
+ filename = g_strconcat (folder_name, ".cmeta", NULL);
+ state_file = g_build_filename (user_data_dir, filename, NULL);
+
+ camel_object_set_state_filename (CAMEL_OBJECT (vf), state_file);
+
+ g_free (state_file);
+ g_free (filename);
+ g_free (folder_name);
+
+ /* set/load persistent state */
+ camel_object_state_read (CAMEL_OBJECT (vf));
+ }
}
/**
@@ -2137,8 +1247,9 @@ camel_vee_folder_new (CamelStore *parent_store,
g_return_val_if_fail (full != NULL, NULL);
if (CAMEL_IS_VEE_STORE (parent_store) && strcmp (full, CAMEL_UNMATCHED_NAME) == 0) {
- vf = ((CamelVeeStore *) parent_store)->folder_unmatched;
- g_object_ref (vf);
+ vf = camel_vee_store_get_unmatched_folder (CAMEL_VEE_STORE (parent_store));
+ if (vf)
+ g_object_ref (vf);
} else {
const gchar *name = strrchr (full, '/');
@@ -2159,173 +1270,111 @@ camel_vee_folder_new (CamelStore *parent_store,
}
void
-camel_vee_folder_set_expression (CamelVeeFolder *vf,
- const gchar *query)
+camel_vee_folder_set_expression (CamelVeeFolder *vfolder,
+ const gchar *expr)
+{
+ CAMEL_VEE_FOLDER_GET_CLASS (vfolder)->set_expression (vfolder, expr);
+}
+
+const gchar *
+camel_vee_folder_get_expression (CamelVeeFolder *vfolder)
{
- CAMEL_VEE_FOLDER_GET_CLASS (vf)->set_expression (vf, query);
+ g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (vfolder), NULL);
+
+ return vfolder->priv->expression;
}
/**
* camel_vee_folder_add_folder:
- * @vf: Virtual Folder object
- * @sub: source CamelFolder to add to @vf
+ * @vfolder: Virtual Folder object
+ * @subfolder: source CamelFolder to add to @vfolder
*
- * Adds @sub as a source folder to @vf.
+ * Adds @subfolder as a source folder to @vfolder.
**/
void
-camel_vee_folder_add_folder (CamelVeeFolder *vf,
- CamelFolder *sub)
+camel_vee_folder_add_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable)
{
- CamelVeeFolderPrivate *p = CAMEL_VEE_FOLDER_GET_PRIVATE (vf);
- gint i;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
- if (vf == (CamelVeeFolder *) sub) {
+ if (vfolder == (CamelVeeFolder *) subfolder) {
g_warning ("Adding a virtual folder to itself as source, ignored");
return;
}
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-
- /* for normal vfolders we want only unique ones, for unmatched we want them all recorded */
- if (g_list_find (p->folders, sub) == NULL) {
- p->folders = g_list_append (
- p->folders, g_object_ref (sub));
-
- camel_folder_lock (CAMEL_FOLDER (vf), CAMEL_FOLDER_CHANGE_LOCK);
-
- /* update the freeze state of 'sub' to match our freeze state */
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) vf); i++)
- camel_folder_freeze (sub);
-
- camel_folder_unlock (CAMEL_FOLDER (vf), CAMEL_FOLDER_CHANGE_LOCK);
- }
- if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0 && !CAMEL_IS_VEE_FOLDER (sub) && folder_unmatched != NULL) {
- CamelVeeFolderPrivate *up = CAMEL_VEE_FOLDER_GET_PRIVATE (folder_unmatched);
- up->folders = g_list_append (
- up->folders, g_object_ref (sub));
-
- camel_folder_lock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
-
- /* update the freeze state of 'sub' to match Unmatched's freeze state */
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) folder_unmatched); i++)
- camel_folder_freeze (sub);
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- camel_folder_unlock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
+ if (g_list_find (vfolder->priv->subfolders, subfolder) == NULL) {
+ vfolder->priv->subfolders = g_list_append (vfolder->priv->subfolders, g_object_ref (subfolder));
+ } else {
+ /* nothing to do, it's already there */
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ return;
}
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-
- g_signal_connect (
- sub, "changed",
- G_CALLBACK (folder_changed), vf);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
g_signal_connect (
- sub, "deleted",
- G_CALLBACK (subfolder_deleted), vf);
+ subfolder, "changed",
+ G_CALLBACK (subfolder_changed), vfolder);
g_signal_connect (
- sub, "renamed",
- G_CALLBACK (folder_renamed), vf);
+ subfolder, "deleted",
+ G_CALLBACK (subfolder_deleted), vfolder);
- CAMEL_VEE_FOLDER_GET_CLASS (vf)->add_folder (vf, sub);
+ CAMEL_VEE_FOLDER_GET_CLASS (vfolder)->add_folder (vfolder, subfolder, cancellable);
}
/**
* camel_vee_folder_remove_folder:
- * @vf: Virtual Folder object
- * @sub: source CamelFolder to remove from @vf
+ * @vfolder: Virtual Folder object
+ * @subfolder: source CamelFolder to remove from @vfolder
*
- * Removed the source folder, @sub, from the virtual folder, @vf.
+ * Removed the source folder, @subfolder, from the virtual folder, @vfolder.
**/
void
-camel_vee_folder_remove_folder (CamelVeeFolder *vf,
- CamelFolder *sub)
+camel_vee_folder_remove_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable)
{
- CamelVeeFolderPrivate *p = CAMEL_VEE_FOLDER_GET_PRIVATE (vf);
- gint i;
- CamelVeeFolder *folder_unmatched = vf->parent_vee_store ? vf->parent_vee_store->folder_unmatched : NULL;
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
-
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- p->folders_changed = g_list_remove (p->folders_changed, sub);
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- if (g_list_find (p->folders, sub) == NULL) {
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ if (g_list_find (vfolder->priv->subfolders, subfolder) == NULL) {
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
return;
}
- g_signal_handlers_disconnect_by_func (sub, folder_changed, vf);
- g_signal_handlers_disconnect_by_func (sub, subfolder_deleted, vf);
- g_signal_handlers_disconnect_by_func (sub, folder_renamed, vf);
-
- p->folders = g_list_remove (p->folders, sub);
-
- /* undo the freeze state that we have imposed on this source folder */
- camel_folder_lock (CAMEL_FOLDER (vf), CAMEL_FOLDER_CHANGE_LOCK);
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) vf); i++)
- camel_folder_thaw (sub);
- camel_folder_unlock (CAMEL_FOLDER (vf), CAMEL_FOLDER_CHANGE_LOCK);
-
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ g_signal_handlers_disconnect_by_func (subfolder, subfolder_changed, vfolder);
+ g_signal_handlers_disconnect_by_func (subfolder, subfolder_deleted, vfolder);
- if (folder_unmatched != NULL) {
- CamelVeeFolderPrivate *up = CAMEL_VEE_FOLDER_GET_PRIVATE (folder_unmatched);
-
- camel_vee_folder_lock (folder_unmatched, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- /* if folder deleted, then blow it away from unmatched always, and remove all refs to it */
- if (sub->folder_flags & CAMEL_FOLDER_HAS_BEEN_DELETED) {
- while (g_list_find (up->folders, sub)) {
- up->folders = g_list_remove (up->folders, sub);
- g_object_unref (sub);
-
- /* undo the freeze state that Unmatched has imposed on this source folder */
- camel_folder_lock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) folder_unmatched); i++)
- camel_folder_thaw (sub);
- camel_folder_unlock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- }
- } else if ((vf->flags & CAMEL_STORE_FOLDER_PRIVATE) == 0) {
- if (g_list_find (up->folders, sub) != NULL) {
- up->folders = g_list_remove (up->folders, sub);
- g_object_unref (sub);
-
- /* undo the freeze state that Unmatched has imposed on this source folder */
- camel_folder_lock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- for (i = 0; i < camel_folder_get_frozen_count ((CamelFolder *) folder_unmatched); i++)
- camel_folder_thaw (sub);
- camel_folder_unlock (CAMEL_FOLDER (folder_unmatched), CAMEL_FOLDER_CHANGE_LOCK);
- }
- }
- camel_vee_folder_unlock (folder_unmatched, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- }
+ vfolder->priv->subfolders = g_list_remove (vfolder->priv->subfolders, subfolder);
- CAMEL_VEE_FOLDER_GET_CLASS (vf)->remove_folder (vf, sub);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- if (CAMEL_IS_VEE_FOLDER (sub))
- return;
+ CAMEL_VEE_FOLDER_GET_CLASS (vfolder)->remove_folder (vfolder, subfolder, cancellable);
- g_object_unref (sub);
+ g_object_unref (subfolder);
}
/**
* camel_vee_folder_rebuild_folder:
- * @vf: Virtual Folder object
- * @sub: source CamelFolder to add to @vf
- * @error: return location for a #GError, or %NULL
+ * @vfolder: Virtual Folder object
+ * @subfolder: source CamelFolder to add to @vfolder
+ * @cancellable:
*
- * Rebuild the folder @sub, if it should be.
+ * Rebuild the folder @subfolder, if it should be.
**/
-gint
-camel_vee_folder_rebuild_folder (CamelVeeFolder *vf,
- CamelFolder *sub,
- GError **error)
+void
+camel_vee_folder_rebuild_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable)
{
- vee_folder_propagate_skipped_changes (vf);
+ vee_folder_propagate_skipped_changes (vfolder);
- return CAMEL_VEE_FOLDER_GET_CLASS (vf)->rebuild_folder (vf, sub, error);
+ CAMEL_VEE_FOLDER_GET_CLASS (vfolder)->rebuild_folder (vfolder, subfolder, cancellable);
}
static void
@@ -2333,7 +1382,7 @@ remove_folders (CamelFolder *folder,
CamelFolder *foldercopy,
CamelVeeFolder *vf)
{
- camel_vee_folder_remove_folder (vf, folder);
+ camel_vee_folder_remove_folder (vf, folder, NULL);
g_object_unref (folder);
}
@@ -2346,16 +1395,17 @@ remove_folders (CamelFolder *folder,
**/
void
camel_vee_folder_set_folders (CamelVeeFolder *vf,
- GList *folders)
+ GList *folders,
+ GCancellable *cancellable)
{
CamelVeeFolderPrivate *p = CAMEL_VEE_FOLDER_GET_PRIVATE (vf);
GHashTable *remove = g_hash_table_new (NULL, NULL);
- GList *l;
+ GList *l, *to_add = NULL;
CamelFolder *folder;
/* setup a table of all folders we have currently */
camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- l = p->folders;
+ l = p->subfolders;
while (l) {
g_hash_table_insert (remove, l->data, l->data);
g_object_ref (l->data);
@@ -2363,66 +1413,117 @@ camel_vee_folder_set_folders (CamelVeeFolder *vf,
}
camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
- /* if we already have the folder, ignore it, otherwise add it */
+ camel_folder_freeze (CAMEL_FOLDER (vf));
+
+ /* if we already have the folder, ignore it, otherwise mark to add it */
l = folders;
while (l) {
if ((folder = g_hash_table_lookup (remove, l->data))) {
g_hash_table_remove (remove, folder);
g_object_unref (folder);
} else {
- camel_vee_folder_add_folder (vf, l->data);
+ to_add = g_list_prepend (to_add, g_object_ref (l->data));
}
l = l->next;
}
- /* then remove any we still have */
+ /* first remove any we still have */
g_hash_table_foreach (remove, (GHFunc) remove_folders, vf);
g_hash_table_destroy (remove);
+
+ /* then add those new */
+ for (l = to_add; l; l = l->next) {
+ camel_vee_folder_add_folder (vf, l->data, cancellable);
+ }
+ g_list_free_full (to_add, g_object_unref);
+
+ camel_folder_thaw (CAMEL_FOLDER (vf));
}
-/**
- * camel_vee_folder_hash_folder:
- * @folder:
- * @:
- *
- * Create a hash string representing the folder name, which should be
- * unique, and remain static for a given folder.
- **/
void
-camel_vee_folder_hash_folder (CamelFolder *folder,
- gchar buffer[8])
+camel_vee_folder_add_vuid (CamelVeeFolder *vfolder,
+ CamelVeeMessageInfoData *mi_data,
+ CamelFolderChangeInfo *changes)
{
- CamelStore *parent_store;
- GChecksum *checksum;
- guint8 *digest;
- gsize length;
- gint state = 0, save = 0;
- const gchar *full_name;
- const gchar *uid;
- gint i;
-
- length = g_checksum_type_get_length (G_CHECKSUM_MD5);
- digest = g_alloca (length);
-
- checksum = g_checksum_new (G_CHECKSUM_MD5);
- parent_store = camel_folder_get_parent_store (folder);
- uid = camel_service_get_uid (CAMEL_SERVICE (parent_store));
- g_checksum_update (checksum, (guchar *) uid, -1);
-
- full_name = camel_folder_get_full_name (folder);
- g_checksum_update (checksum, (guchar *) full_name, -1);
- g_checksum_get_digest (checksum, digest, &length);
- g_checksum_free (checksum);
-
- g_base64_encode_step (digest, 6, FALSE, buffer, &state, &save);
- g_base64_encode_close (FALSE, buffer, &state, &save);
-
- for (i = 0; i < 8; i++) {
- if (buffer[i] == '+')
- buffer[i] = '.';
- if (buffer[i] == '/')
- buffer[i] = '_';
+ CamelVeeSummary *vsummary;
+ CamelVeeSubfolderData *sf_data;
+ CamelFolder *subfolder;
+
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
+ g_return_if_fail (mi_data != NULL);
+ g_return_if_fail (vee_folder_is_unmatched (vfolder));
+
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ subfolder = camel_vee_subfolder_data_get_folder (sf_data);
+
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ if (!camel_vee_folder_get_auto_update (vfolder) ||
+ g_hash_table_lookup (vfolder->priv->ignore_changed, subfolder) ||
+ g_hash_table_lookup (vfolder->priv->skipped_changes, subfolder)) {
+ g_hash_table_remove (vfolder->priv->unmatched_remove_changed, mi_data);
+
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+
+ if (g_list_find (vfolder->priv->subfolders, subfolder)) {
+ /* postpone addition to the Unmatched folder, if the change was done
+ in the Unmatched folder itself or auto-update is disabled */
+ g_hash_table_insert (vfolder->priv->unmatched_add_changed,
+ g_object_ref (mi_data), GINT_TO_POINTER (1));
+ }
+
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+
+ return;
+ }
+
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+
+ vsummary = CAMEL_VEE_SUMMARY (CAMEL_FOLDER (vfolder)->summary);
+ vee_folder_note_added_uid (vfolder, vsummary, mi_data, changes, FALSE);
+}
+
+void
+camel_vee_folder_remove_vuid (CamelVeeFolder *vfolder,
+ CamelVeeMessageInfoData *mi_data,
+ CamelFolderChangeInfo *changes)
+{
+ CamelVeeSummary *vsummary;
+ CamelVeeSubfolderData *sf_data;
+ CamelFolder *subfolder;
+
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
+ g_return_if_fail (mi_data != NULL);
+ g_return_if_fail (vee_folder_is_unmatched (vfolder));
+
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ subfolder = camel_vee_subfolder_data_get_folder (sf_data);
+
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ if (!camel_vee_folder_get_auto_update (vfolder) ||
+ g_hash_table_lookup (vfolder->priv->ignore_changed, subfolder) ||
+ g_hash_table_lookup (vfolder->priv->skipped_changes, subfolder)) {
+ g_hash_table_remove (vfolder->priv->unmatched_add_changed, mi_data);
+
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+
+ if (g_list_find (vfolder->priv->subfolders, subfolder)) {
+ /* postpone removal from the Unmatched folder, if the change was done
+ in the Unmatched folder itself or auto-update is disabled */
+ g_hash_table_insert (vfolder->priv->unmatched_remove_changed,
+ g_object_ref (mi_data), GINT_TO_POINTER (1));
+ }
+
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_SUBFOLDER_LOCK);
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+
+ return;
}
+
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+
+ vsummary = CAMEL_VEE_SUMMARY (CAMEL_FOLDER (vfolder)->summary);
+ vee_folder_note_unmatch_uid (vfolder, vsummary, subfolder, mi_data, changes);
}
/**
@@ -2443,6 +1544,9 @@ camel_vee_folder_get_location (CamelVeeFolder *vf,
{
CamelFolder *folder;
+ g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (vf), NULL);
+ g_return_val_if_fail (vinfo != NULL, NULL);
+
folder = camel_folder_summary_get_folder (vinfo->orig_summary);
/* locking? yes? no? although the vfolderinfo is valid when obtained
@@ -2463,12 +1567,61 @@ camel_vee_folder_get_location (CamelVeeFolder *vf,
}
}
+CamelFolder *
+camel_vee_folder_get_vee_uid_folder (CamelVeeFolder *vf,
+ const gchar *vee_message_uid)
+{
+ CamelFolder *res;
+ CamelVeeDataCache *data_cache;
+ CamelVeeMessageInfoData *mi_data;
+ CamelVeeSubfolderData *sf_data;
+
+ g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (vf), NULL);
+ g_return_val_if_fail (vee_message_uid, NULL);
+
+ res = NULL;
+
+ data_cache = vee_folder_get_data_cache (vf);
+ g_return_val_if_fail (data_cache != NULL, NULL);
+
+ mi_data = camel_vee_data_cache_get_message_info_data_by_vuid (data_cache, vee_message_uid);
+ if (mi_data) {
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ res = camel_vee_subfolder_data_get_folder (sf_data);
+ g_object_unref (mi_data);
+ }
+
+ return res;
+}
+
+void
+camel_vee_folder_set_auto_update (CamelVeeFolder *vfolder,
+ gboolean auto_update)
+{
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
+
+ if ((vfolder->priv->auto_update ? 1 : 0) == (auto_update ? 1 : 0))
+ return;
+
+ vfolder->priv->auto_update = auto_update;
+
+ g_object_notify (G_OBJECT (vfolder), "auto-update");
+}
+
+gboolean
+camel_vee_folder_get_auto_update (CamelVeeFolder *vfolder)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (vfolder), FALSE);
+
+ return vfolder->priv->auto_update;
+}
+
/**
* camel_vee_folder_ignore_next_changed_event:
- * @vf: a #CamelVeeFolder
- * @sub: a #CamelFolder folder
+ * @vfolder: a #CamelVeeFolder
+ * @subfolder: a #CamelFolder folder
*
- * The next @sub folder's 'changed' event will be silently ignored. This
+ * The next @subfolder-'s 'changed' event will be silently ignored. This
* is usually used in virtual folders when the change was done in them,
* but it is neither vTrash nor vJunk folder. Doing this avoids unnecessary
* removals of messages which don't satisfy search criteria anymore,
@@ -2478,39 +1631,15 @@ camel_vee_folder_get_location (CamelVeeFolder *vf,
* Since: 3.2
**/
void
-camel_vee_folder_ignore_next_changed_event (CamelVeeFolder *vf,
- CamelFolder *sub)
-{
- g_return_if_fail (vf != NULL);
- g_return_if_fail (CAMEL_IS_VEE_FOLDER (vf));
- g_return_if_fail (sub != NULL);
-
- camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
- g_hash_table_insert (vf->priv->ignore_changed, sub, GINT_TO_POINTER (1));
- camel_vee_folder_unlock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK);
-}
-
-/**
- * camel_vee_folder_sync_headers:
- *
- * Since: 2.24
- **/
-void
-camel_vee_folder_sync_headers (CamelFolder *vf,
- GError **error)
+camel_vee_folder_ignore_next_changed_event (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder)
{
- CamelFIRecord * record;
- CamelStore *parent_store;
-
- /* Save the counts to DB */
- record = summary_header_to_db (vf->summary, error);
- parent_store = camel_folder_get_parent_store (vf);
- camel_db_begin_transaction (parent_store->cdb_w, NULL);
- camel_db_write_folder_info_record (parent_store->cdb_w, record, error);
- camel_db_end_transaction (parent_store->cdb_w, NULL);
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (vfolder));
+ g_return_if_fail (subfolder != NULL);
- g_free (record->folder_name);
- g_free (record);
+ camel_vee_folder_lock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
+ g_hash_table_insert (vfolder->priv->ignore_changed, subfolder, GINT_TO_POINTER (1));
+ camel_vee_folder_unlock (vfolder, CAMEL_VEE_FOLDER_CHANGED_LOCK);
}
/**
@@ -2530,13 +1659,13 @@ camel_vee_folder_lock (CamelVeeFolder *folder,
switch (lock) {
case CAMEL_VEE_FOLDER_SUMMARY_LOCK:
- g_mutex_lock (folder->priv->summary_lock);
+ g_static_rec_mutex_lock (&folder->priv->summary_lock);
break;
case CAMEL_VEE_FOLDER_SUBFOLDER_LOCK:
- g_mutex_lock (folder->priv->subfolder_lock);
+ g_static_rec_mutex_lock (&folder->priv->subfolder_lock);
break;
case CAMEL_VEE_FOLDER_CHANGED_LOCK:
- g_mutex_lock (folder->priv->changed_lock);
+ g_static_rec_mutex_lock (&folder->priv->changed_lock);
break;
default:
g_return_if_reached ();
@@ -2560,13 +1689,13 @@ camel_vee_folder_unlock (CamelVeeFolder *folder,
switch (lock) {
case CAMEL_VEE_FOLDER_SUMMARY_LOCK:
- g_mutex_unlock (folder->priv->summary_lock);
+ g_static_rec_mutex_unlock (&folder->priv->summary_lock);
break;
case CAMEL_VEE_FOLDER_SUBFOLDER_LOCK:
- g_mutex_unlock (folder->priv->subfolder_lock);
+ g_static_rec_mutex_unlock (&folder->priv->subfolder_lock);
break;
case CAMEL_VEE_FOLDER_CHANGED_LOCK:
- g_mutex_unlock (folder->priv->changed_lock);
+ g_static_rec_mutex_unlock (&folder->priv->changed_lock);
break;
default:
g_return_if_reached ();
diff --git a/camel/camel-vee-folder.h b/camel/camel-vee-folder.h
index 8999c1a..ea452ef 100644
--- a/camel/camel-vee-folder.h
+++ b/camel/camel-vee-folder.h
@@ -71,19 +71,7 @@ struct _CamelVeeFolder {
CamelFolder parent;
CamelVeeFolderPrivate *priv;
- gchar *expression; /* query expression */
-
guint32 flags; /* folder open flags */
-
- CamelFolderChangeInfo *changes;
- CamelFolderSearch *search;
-
- /* only set-up if our parent is a vee-store, used also as a flag to
- * say that this folder is part of the unmatched folder */
- struct _CamelVeeStore *parent_vee_store;
- GHashTable *hashes;
- GHashTable *loaded;
- gboolean deleted;
};
struct _CamelVeeFolderClass {
@@ -92,12 +80,14 @@ struct _CamelVeeFolderClass {
/* TODO: Some of this may need some additional work/thinking through, it works for now*/
void (*add_folder) (CamelVeeFolder *vee_folder,
- CamelFolder *folder);
+ CamelFolder *folder,
+ GCancellable *cancellable);
void (*remove_folder) (CamelVeeFolder *vee_folder,
- CamelFolder *folder);
- gint (*rebuild_folder) (CamelVeeFolder *vee_folder,
CamelFolder *folder,
- GError **error);
+ GCancellable *cancellable);
+ void (*rebuild_folder) (CamelVeeFolder *vee_folder,
+ CamelFolder *folder,
+ GCancellable *cancellable);
void (*set_expression) (CamelVeeFolder *vee_folder,
const gchar *expression);
@@ -106,34 +96,56 @@ struct _CamelVeeFolderClass {
void (*folder_changed) (CamelVeeFolder *vee_folder,
CamelFolder *subfolder,
CamelFolderChangeInfo *changes);
- /* Called for a folder-renamed event on a source folder */
- void (*folder_renamed) (CamelVeeFolder *vee_folder,
- CamelFolder *subfolder,
- const gchar *old);
};
#define CAMEL_UNMATCHED_NAME "UNMATCHED"
-GType camel_vee_folder_get_type (void);
-CamelFolder *camel_vee_folder_new (CamelStore *parent_store, const gchar *full, guint32 flags);
-void camel_vee_folder_construct (CamelVeeFolder *vf, guint32 flags);
-
-CamelFolder *camel_vee_folder_get_location (CamelVeeFolder *vf, const struct _CamelVeeMessageInfo *vinfo, gchar **realuid);
-
-void camel_vee_folder_add_folder (CamelVeeFolder *vf, CamelFolder *sub);
-void camel_vee_folder_remove_folder (CamelVeeFolder *vf,
- CamelFolder *sub);
-void camel_vee_folder_set_folders (CamelVeeFolder *vf, GList *folders);
-gint camel_vee_folder_rebuild_folder (CamelVeeFolder *vf, CamelFolder *sub, GError **error);
-void camel_vee_folder_set_expression (CamelVeeFolder *vf, const gchar *expr);
-
-void camel_vee_folder_ignore_next_changed_event (CamelVeeFolder *vf, CamelFolder *sub);
-
-void camel_vee_folder_hash_folder (CamelFolder *folder, gchar buffer[8]);
-void camel_vee_folder_sync_headers (CamelFolder *vf, GError **error);
-
-void camel_vee_folder_lock (CamelVeeFolder *folder, CamelVeeFolderLock lock);
-void camel_vee_folder_unlock (CamelVeeFolder *folder, CamelVeeFolderLock lock);
+GType camel_vee_folder_get_type (void);
+CamelFolder * camel_vee_folder_new (CamelStore *parent_store,
+ const gchar *full,
+ guint32 flags);
+void camel_vee_folder_construct (CamelVeeFolder *vf,
+ guint32 flags);
+
+CamelFolder * camel_vee_folder_get_location (CamelVeeFolder *vf,
+ const struct _CamelVeeMessageInfo *vinfo,
+ gchar **realuid);
+CamelFolder * camel_vee_folder_get_vee_uid_folder (CamelVeeFolder *vf,
+ const gchar *vee_message_uid);
+void camel_vee_folder_set_auto_update (CamelVeeFolder *vfolder,
+ gboolean auto_update);
+gboolean camel_vee_folder_get_auto_update (CamelVeeFolder *vfolder);
+void camel_vee_folder_add_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable);
+void camel_vee_folder_remove_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable);
+void camel_vee_folder_set_folders (CamelVeeFolder *vf,
+ GList *folders,
+ GCancellable *cancellable);
+void camel_vee_folder_add_vuid (CamelVeeFolder *vfolder,
+ struct _CamelVeeMessageInfoData *mi_data,
+ CamelFolderChangeInfo *changes);
+void camel_vee_folder_remove_vuid (CamelVeeFolder *vfolder,
+ struct _CamelVeeMessageInfoData *mi_data,
+ CamelFolderChangeInfo *changes);
+
+void camel_vee_folder_rebuild_folder (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder,
+ GCancellable *cancellable);
+void camel_vee_folder_set_expression (CamelVeeFolder *vfolder,
+ const gchar *expr);
+const gchar * camel_vee_folder_get_expression (CamelVeeFolder *vfolder);
+
+void camel_vee_folder_ignore_next_changed_event
+ (CamelVeeFolder *vfolder,
+ CamelFolder *subfolder);
+
+void camel_vee_folder_lock (CamelVeeFolder *folder,
+ CamelVeeFolderLock lock);
+void camel_vee_folder_unlock (CamelVeeFolder *folder,
+ CamelVeeFolderLock lock);
G_END_DECLS
diff --git a/camel/camel-vee-store.c b/camel/camel-vee-store.c
index 7e30e99..bd8f481 100644
--- a/camel/camel-vee-store.c
+++ b/camel/camel-vee-store.c
@@ -29,6 +29,7 @@
#include "camel-db.h"
#include "camel-session.h"
+#include "camel-string-utils.h"
#include "camel-vee-folder.h"
#include "camel-vee-store.h"
@@ -46,8 +47,28 @@
#define CHANGE_DELETE (1)
#define CHANGE_NOSELECT (2)
+/* The custom property ID is a CamelArg artifact.
+ * It still identifies the property in state files. */
+enum {
+ PROP_0,
+ PROP_UNMATCHED_ENABLED = 0x2400
+};
+
G_DEFINE_TYPE (CamelVeeStore, camel_vee_store, CAMEL_TYPE_STORE)
+struct _CamelVeeStorePrivate
+{
+ CamelVeeDataCache *vee_data_cache;
+ CamelVeeFolder *unmatched_folder;
+ gboolean unmatched_enabled;
+
+ GMutex *sf_counts_mutex;
+ GHashTable *subfolder_usage_counts; /* CamelFolder * (subfolder) => gint of usages, for unmatched_folder */
+
+ GMutex *vu_counts_mutex;
+ GHashTable *vuid_usage_counts; /* gchar * (vuid) => gint of usages, those with 0 comes to unmatched_folder */
+};
+
static gint
vee_folder_cmp (gconstpointer ap,
gconstpointer bp)
@@ -92,21 +113,16 @@ change_folder (CamelStore *store,
}
static void
-cvs_free_unmatched (gpointer key,
- gpointer value,
- gpointer data)
-{
- g_free (key);
-}
-
-static void
vee_store_finalize (GObject *object)
{
CamelVeeStore *vee_store = CAMEL_VEE_STORE (object);
- g_hash_table_foreach (vee_store->unmatched_uids, cvs_free_unmatched, NULL);
- g_hash_table_destroy (vee_store->unmatched_uids);
- g_object_unref (vee_store->folder_unmatched);
+ g_object_unref (vee_store->priv->unmatched_folder);
+ g_object_unref (vee_store->priv->vee_data_cache);
+ g_hash_table_destroy (vee_store->priv->subfolder_usage_counts);
+ g_hash_table_destroy (vee_store->priv->vuid_usage_counts);
+ g_mutex_free (vee_store->priv->sf_counts_mutex);
+ g_mutex_free (vee_store->priv->vu_counts_mutex);
/* Chain up to parent's finalize () method. */
G_OBJECT_CLASS (camel_vee_store_parent_class)->finalize (object);
@@ -122,20 +138,52 @@ vee_store_constructed (GObject *object)
/* Chain up to parent's constructed() method. */
G_OBJECT_CLASS (camel_vee_store_parent_class)->constructed (object);
-#ifndef VEE_UNMATCHED_ENABLE
/* Set up unmatched folder */
- vee_store->unmatched_uids = g_hash_table_new (g_str_hash, g_str_equal);
- vee_store->folder_unmatched = g_object_new (
+ vee_store->priv->unmatched_folder = g_object_new (
CAMEL_TYPE_VEE_FOLDER,
"full-name", CAMEL_UNMATCHED_NAME,
"display-name", PRETTY_UNMATCHED_FOLDER_NAME,
"parent-store", vee_store, NULL);
camel_vee_folder_construct (
- vee_store->folder_unmatched, CAMEL_STORE_FOLDER_PRIVATE);
- camel_db_create_vfolder (
- CAMEL_STORE (vee_store)->cdb_r, PRETTY_UNMATCHED_FOLDER_NAME, NULL);
-#endif
+ vee_store->priv->unmatched_folder, CAMEL_STORE_FOLDER_PRIVATE);
+ vee_store->priv->subfolder_usage_counts = g_hash_table_new (g_direct_hash, g_direct_equal);
+ vee_store->priv->vuid_usage_counts = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) camel_pstring_free, NULL);
+ vee_store->priv->sf_counts_mutex = g_mutex_new ();
+ vee_store->priv->vu_counts_mutex = g_mutex_new ();
+}
+
+static void
+vee_store_get_property (GObject *object,
+ guint property_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_UNMATCHED_ENABLED:
+ g_value_set_boolean (
+ value, camel_vee_store_get_unmatched_enabled (
+ CAMEL_VEE_STORE (object)));
+ return;
+ }
+
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+}
+
+static void
+vee_store_set_property (GObject *object,
+ guint property_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ switch (property_id) {
+ case PROP_UNMATCHED_ENABLED:
+ camel_vee_store_set_unmatched_enabled (
+ CAMEL_VEE_STORE (object),
+ g_value_get_boolean (value));
+ return;
+ }
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
}
static gchar *
@@ -189,6 +237,24 @@ vee_store_get_folder_sync (CamelStore *store,
}
static CamelFolderInfo *
+vee_store_create_unmatched_fi (void)
+{
+ CamelFolderInfo *info;
+
+ info = camel_folder_info_new ();
+ info->full_name = g_strdup (CAMEL_UNMATCHED_NAME);
+ info->display_name = g_strdup (PRETTY_UNMATCHED_FOLDER_NAME);
+ info->unread = -1;
+ info->flags =
+ CAMEL_FOLDER_NOCHILDREN |
+ CAMEL_FOLDER_NOINFERIORS |
+ CAMEL_FOLDER_SYSTEM |
+ CAMEL_FOLDER_VIRTUAL;
+
+ return info;
+}
+
+static CamelFolderInfo *
vee_store_get_folder_info_sync (CamelStore *store,
const gchar *top,
CamelStoreGetFolderInfoFlags flags,
@@ -295,18 +361,10 @@ vee_store_get_folder_info_sync (CamelStore *store,
g_ptr_array_free (folders, TRUE);
g_hash_table_destroy (infos_hash);
- /* and always add UNMATCHED, if scanning from top/etc */
- /* FIXME[disk-summary] comment it out well */
- if ((top == NULL || top[0] == 0 || strncmp (top, CAMEL_UNMATCHED_NAME, strlen (CAMEL_UNMATCHED_NAME)) == 0)) {
- info = camel_folder_info_new ();
- info->full_name = g_strdup (CAMEL_UNMATCHED_NAME);
- info->display_name = g_strdup (PRETTY_UNMATCHED_FOLDER_NAME);
- info->unread = -1;
- info->flags =
- CAMEL_FOLDER_NOCHILDREN |
- CAMEL_FOLDER_NOINFERIORS |
- CAMEL_FOLDER_SYSTEM |
- CAMEL_FOLDER_VIRTUAL;
+ /* and add UNMATCHED, if scanning from top/etc and it's enabled */
+ if (camel_vee_store_get_unmatched_enabled (CAMEL_VEE_STORE (store)) &&
+ (top == NULL || top[0] == 0 || strncmp (top, CAMEL_UNMATCHED_NAME, strlen (CAMEL_UNMATCHED_NAME)) == 0)) {
+ info = vee_store_create_unmatched_fi ();
if (res == NULL)
res = info;
@@ -445,9 +503,13 @@ camel_vee_store_class_init (CamelVeeStoreClass *class)
CamelServiceClass *service_class;
CamelStoreClass *store_class;
+ g_type_class_add_private (class, sizeof (CamelVeeStorePrivate));
+
object_class = G_OBJECT_CLASS (class);
object_class->finalize = vee_store_finalize;
object_class->constructed = vee_store_constructed;
+ object_class->get_property = vee_store_get_property;
+ object_class->set_property = vee_store_set_property;
service_class = CAMEL_SERVICE_CLASS (class);
service_class->get_name = vee_store_get_name;
@@ -460,6 +522,16 @@ 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;
+
+ g_object_class_install_property (
+ object_class,
+ PROP_UNMATCHED_ENABLED,
+ g_param_spec_boolean (
+ "unmatched-enabled",
+ "Unmatched Enabled",
+ _("Enable _Unmatched folder"),
+ TRUE,
+ G_PARAM_READWRITE));
}
static void
@@ -467,6 +539,10 @@ camel_vee_store_init (CamelVeeStore *vee_store)
{
CamelStore *store = CAMEL_STORE (vee_store);
+ vee_store->priv = G_TYPE_INSTANCE_GET_PRIVATE (vee_store, CAMEL_TYPE_VEE_STORE, CamelVeeStorePrivate);
+ vee_store->priv->vee_data_cache = camel_vee_data_cache_new ();
+ vee_store->priv->unmatched_enabled = TRUE;
+
/* we dont want a vtrash/vjunk on this one */
store->flags &= ~(CAMEL_STORE_VTRASH | CAMEL_STORE_VJUNK);
}
@@ -483,3 +559,399 @@ camel_vee_store_new (void)
{
return g_object_new (CAMEL_TYPE_VEE_STORE, NULL);
}
+
+CamelVeeDataCache *
+camel_vee_store_get_vee_data_cache (CamelVeeStore *vstore)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_STORE (vstore), NULL);
+
+ return vstore->priv->vee_data_cache;
+}
+
+CamelVeeFolder *
+camel_vee_store_get_unmatched_folder (CamelVeeStore *vstore)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_STORE (vstore), NULL);
+
+ if (!camel_vee_store_get_unmatched_enabled (vstore))
+ return NULL;
+
+ return vstore->priv->unmatched_folder;
+}
+
+gboolean
+camel_vee_store_get_unmatched_enabled (CamelVeeStore *vstore)
+{
+ g_return_val_if_fail (CAMEL_IS_VEE_STORE (vstore), FALSE);
+
+ return vstore->priv->unmatched_enabled;
+}
+
+void
+camel_vee_store_set_unmatched_enabled (CamelVeeStore *vstore,
+ gboolean is_enabled)
+{
+ CamelFolderInfo *fi_unmatched;
+
+ g_return_if_fail (CAMEL_IS_VEE_STORE (vstore));
+
+ if ((vstore->priv->unmatched_enabled ? 1 : 0) == (is_enabled ? 1 : 0))
+ return;
+
+ vstore->priv->unmatched_enabled = is_enabled;
+ g_object_notify (G_OBJECT (vstore), "unmatched-enabled");
+
+ fi_unmatched = vee_store_create_unmatched_fi ();
+
+ if (is_enabled) {
+ camel_store_folder_created (CAMEL_STORE (vstore), fi_unmatched);
+ camel_vee_store_rebuild_unmatched_folder (vstore, NULL, NULL);
+ } else {
+ camel_store_folder_deleted (CAMEL_STORE (vstore), fi_unmatched);
+ }
+
+ camel_folder_info_free (fi_unmatched);
+}
+
+struct AddToUnmatchedData
+{
+ CamelVeeFolder *unmatched_folder;
+ CamelFolderChangeInfo *changes;
+ gboolean unmatched_enabled;
+ GHashTable *vuid_usage_counts;
+};
+
+static void
+add_to_unmatched_folder_cb (CamelVeeMessageInfoData *mi_data,
+ CamelFolder *subfolder,
+ gpointer user_data)
+{
+ struct AddToUnmatchedData *atud = user_data;
+ const gchar *vuid;
+
+ g_return_if_fail (atud != NULL);
+
+ vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
+ g_hash_table_insert (atud->vuid_usage_counts,
+ (gpointer) camel_pstring_strdup (vuid), GINT_TO_POINTER (0));
+
+ if (atud->unmatched_enabled)
+ camel_vee_folder_add_vuid (atud->unmatched_folder, mi_data, atud->changes);
+}
+
+void
+camel_vee_store_note_subfolder_used (CamelVeeStore *vstore,
+ CamelFolder *subfolder,
+ CamelVeeFolder *used_by)
+{
+ gint counts;
+
+ g_return_if_fail (CAMEL_IS_VEE_STORE (vstore));
+ g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (used_by));
+
+ /* only real folders can be part of the unmatched folder */
+ if (CAMEL_IS_VEE_FOLDER (subfolder) ||
+ used_by == vstore->priv->unmatched_folder)
+ return;
+
+ g_mutex_lock (vstore->priv->sf_counts_mutex);
+
+ counts = GPOINTER_TO_INT (g_hash_table_lookup (vstore->priv->subfolder_usage_counts, subfolder));
+ counts++;
+ g_hash_table_insert (vstore->priv->subfolder_usage_counts, subfolder, GINT_TO_POINTER (counts));
+
+ if (counts == 1) {
+ struct AddToUnmatchedData atud;
+ CamelFolder *unmatched_folder;
+
+ camel_vee_data_cache_add_subfolder (vstore->priv->vee_data_cache, subfolder);
+
+ g_mutex_lock (vstore->priv->vu_counts_mutex);
+
+ /* all messages from the folder are unmatched at the beginning */
+ atud.unmatched_folder = vstore->priv->unmatched_folder;
+ atud.changes = camel_folder_change_info_new ();
+ atud.unmatched_enabled = camel_vee_store_get_unmatched_enabled (vstore);
+ atud.vuid_usage_counts = vstore->priv->vuid_usage_counts;
+
+ if (atud.unmatched_enabled)
+ camel_vee_folder_add_folder (vstore->priv->unmatched_folder, subfolder, NULL);
+
+ unmatched_folder = CAMEL_FOLDER (atud.unmatched_folder);
+
+ camel_folder_freeze (unmatched_folder);
+
+ camel_vee_data_cache_foreach_message_info_data (vstore->priv->vee_data_cache, subfolder,
+ add_to_unmatched_folder_cb, &atud);
+
+ camel_folder_thaw (unmatched_folder);
+ g_mutex_unlock (vstore->priv->vu_counts_mutex);
+
+ if (camel_folder_change_info_changed (atud.changes))
+ camel_folder_changed (unmatched_folder, atud.changes);
+ camel_folder_change_info_free (atud.changes);
+ }
+
+ g_mutex_unlock (vstore->priv->sf_counts_mutex);
+}
+
+static void
+remove_vuid_count_record_cb (CamelVeeMessageInfoData *mi_data,
+ CamelFolder *subfolder,
+ gpointer user_data)
+{
+ GHashTable *vuid_usage_counts = user_data;
+
+ g_return_if_fail (mi_data != NULL);
+ g_return_if_fail (user_data != NULL);
+
+ g_hash_table_remove (vuid_usage_counts, camel_vee_message_info_data_get_vee_message_uid (mi_data));
+}
+
+void
+camel_vee_store_note_subfolder_unused (CamelVeeStore *vstore,
+ CamelFolder *subfolder,
+ CamelVeeFolder *unused_by)
+{
+ gint counts;
+
+ g_return_if_fail (CAMEL_IS_VEE_STORE (vstore));
+ g_return_if_fail (CAMEL_IS_FOLDER (subfolder));
+ g_return_if_fail (CAMEL_IS_VEE_FOLDER (unused_by));
+
+ /* only real folders can be part of the unmatched folder */
+ if (CAMEL_IS_VEE_FOLDER (subfolder) ||
+ unused_by == vstore->priv->unmatched_folder)
+ return;
+
+ g_mutex_lock (vstore->priv->sf_counts_mutex);
+
+ counts = GPOINTER_TO_INT (g_hash_table_lookup (vstore->priv->subfolder_usage_counts, subfolder));
+ g_return_if_fail (counts > 0);
+
+ counts--;
+ if (counts == 0) {
+ g_hash_table_remove (vstore->priv->subfolder_usage_counts, subfolder);
+ if (camel_vee_store_get_unmatched_enabled (vstore))
+ camel_vee_folder_remove_folder (vstore->priv->unmatched_folder, subfolder, NULL);
+
+ g_mutex_lock (vstore->priv->vu_counts_mutex);
+ camel_vee_data_cache_foreach_message_info_data (vstore->priv->vee_data_cache, subfolder,
+ remove_vuid_count_record_cb, vstore->priv->vuid_usage_counts);
+ g_mutex_unlock (vstore->priv->vu_counts_mutex);
+
+ camel_vee_data_cache_remove_subfolder (vstore->priv->vee_data_cache, subfolder);
+ } else {
+ g_hash_table_insert (vstore->priv->subfolder_usage_counts, subfolder, GINT_TO_POINTER (counts));
+ }
+
+ g_mutex_unlock (vstore->priv->sf_counts_mutex);
+}
+
+void
+camel_vee_store_note_vuid_used (CamelVeeStore *vstore,
+ CamelVeeMessageInfoData *mi_data,
+ CamelVeeFolder *used_by)
+{
+ gint counts;
+ const gchar *vuid;
+ CamelFolder *subfolder;
+ CamelVeeSubfolderData *sf_data;
+
+ g_return_if_fail (CAMEL_IS_VEE_STORE (vstore));
+ g_return_if_fail (used_by != NULL);
+ g_return_if_fail (mi_data != NULL);
+
+ /* these notifications are ignored from Unmatched folder */
+ if (used_by == vstore->priv->unmatched_folder)
+ return;
+
+ /* unmatched folder holds only real folders */
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ subfolder = camel_vee_subfolder_data_get_folder (sf_data);
+ if (CAMEL_IS_VEE_FOLDER (subfolder))
+ return;
+
+ g_mutex_lock (vstore->priv->vu_counts_mutex);
+
+ vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
+
+ counts = GPOINTER_TO_INT (g_hash_table_lookup (vstore->priv->vuid_usage_counts, vuid));
+ counts++;
+ g_hash_table_insert (vstore->priv->vuid_usage_counts,
+ (gpointer) camel_pstring_strdup (vuid), GINT_TO_POINTER (counts));
+
+ if (counts == 1 && camel_vee_store_get_unmatched_enabled (vstore)) {
+ CamelFolderChangeInfo *changes;
+
+ changes = camel_folder_change_info_new ();
+
+ camel_vee_folder_remove_vuid (vstore->priv->unmatched_folder, mi_data, changes);
+
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (CAMEL_FOLDER (vstore->priv->unmatched_folder), changes);
+ camel_folder_change_info_free (changes);
+ }
+
+ g_mutex_unlock (vstore->priv->vu_counts_mutex);
+}
+
+void
+camel_vee_store_note_vuid_unused (CamelVeeStore *vstore,
+ CamelVeeMessageInfoData *mi_data,
+ CamelVeeFolder *unused_by)
+{
+ gint counts;
+ const gchar *vuid;
+ CamelFolder *subfolder;
+ CamelVeeSubfolderData *sf_data;
+
+ g_return_if_fail (CAMEL_IS_VEE_STORE (vstore));
+ g_return_if_fail (unused_by != NULL);
+ g_return_if_fail (mi_data != NULL);
+
+ /* these notifications are ignored from Unmatched folder */
+ if (unused_by == vstore->priv->unmatched_folder)
+ return;
+
+ /* unmatched folder holds only real folders */
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ subfolder = camel_vee_subfolder_data_get_folder (sf_data);
+ if (CAMEL_IS_VEE_FOLDER (subfolder))
+ return;
+
+ g_mutex_lock (vstore->priv->vu_counts_mutex);
+
+ vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
+
+ counts = GPOINTER_TO_INT (g_hash_table_lookup (vstore->priv->vuid_usage_counts, vuid));
+ counts--;
+ if (counts < 0) {
+ g_mutex_unlock (vstore->priv->vu_counts_mutex);
+ g_return_if_fail (counts >= 0);
+ return;
+ }
+
+ g_hash_table_insert (vstore->priv->vuid_usage_counts,
+ (gpointer) camel_pstring_strdup (vuid), GINT_TO_POINTER (counts));
+
+ if (counts == 0 && camel_vee_store_get_unmatched_enabled (vstore)) {
+ CamelFolderChangeInfo *changes;
+
+ changes = camel_folder_change_info_new ();
+
+ camel_vee_folder_add_vuid (vstore->priv->unmatched_folder, mi_data, changes);
+
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (CAMEL_FOLDER (vstore->priv->unmatched_folder), changes);
+ camel_folder_change_info_free (changes);
+ }
+
+ g_mutex_unlock (vstore->priv->vu_counts_mutex);
+}
+
+struct RebuildUnmatchedData
+{
+ CamelVeeDataCache *data_cache;
+ CamelVeeFolder *unmatched_folder;
+ CamelFolderChangeInfo *changes;
+ GCancellable *cancellable;
+};
+
+static void
+rebuild_unmatched_folder_cb (gpointer key,
+ gpointer value,
+ gpointer user_data)
+{
+ const gchar *vuid = key;
+ gint counts = GPOINTER_TO_INT (value);
+ struct RebuildUnmatchedData *rud = user_data;
+ CamelVeeSubfolderData *si_data;
+ CamelVeeMessageInfoData *mi_data;
+
+ g_return_if_fail (vuid != NULL);
+ g_return_if_fail (rud != NULL);
+
+ if (counts != 0 || g_cancellable_is_cancelled (rud->cancellable))
+ return;
+
+ mi_data = camel_vee_data_cache_get_message_info_data_by_vuid (rud->data_cache, vuid);
+ if (!mi_data)
+ return;
+
+ si_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+
+ camel_vee_folder_add_folder (rud->unmatched_folder, camel_vee_subfolder_data_get_folder (si_data), NULL);
+ camel_vee_folder_add_vuid (rud->unmatched_folder, mi_data, rud->changes);
+
+ g_object_unref (mi_data);
+}
+
+static void
+vee_store_rebuild_unmatched_folder (CamelSession *session,
+ GCancellable *cancellable,
+ CamelVeeStore *vstore,
+ GError **error)
+{
+ struct RebuildUnmatchedData rud;
+ CamelVeeFolder *vunmatched;
+ CamelFolder *unmatched_folder;
+ CamelFolderChangeInfo *changes;
+
+ g_return_if_fail (CAMEL_IS_VEE_STORE (vstore));
+
+ vunmatched = camel_vee_store_get_unmatched_folder (vstore);
+ /* someone could disable it meanwhile */
+ if (!vunmatched)
+ return;
+
+ unmatched_folder = CAMEL_FOLDER (vunmatched);
+ g_return_if_fail (unmatched_folder != NULL);
+
+ camel_folder_freeze (unmatched_folder);
+
+ /* start from scratch, with empty folder */
+ camel_vee_folder_set_folders (vunmatched, NULL, cancellable);
+
+ changes = camel_folder_change_info_new ();
+
+ rud.data_cache = vstore->priv->vee_data_cache;
+ rud.unmatched_folder = vunmatched;
+ rud.changes = changes;
+ rud.cancellable = cancellable;
+
+ g_hash_table_foreach (vstore->priv->vuid_usage_counts, rebuild_unmatched_folder_cb, &rud);
+
+ camel_folder_thaw (unmatched_folder);
+
+ if (camel_folder_change_info_changed (changes))
+ camel_folder_changed (unmatched_folder, changes);
+ camel_folder_change_info_free (changes);
+
+ g_cancellable_set_error_if_cancelled (cancellable, error);
+}
+
+void
+camel_vee_store_rebuild_unmatched_folder (CamelVeeStore *vstore,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_if_fail (CAMEL_IS_VEE_STORE (vstore));
+
+ /* this operation requires cancellable, thus if called
+ without it then run in a dedicated thread */
+ if (!cancellable) {
+ CamelSession *session;
+
+ session = camel_service_get_session (CAMEL_SERVICE (vstore));
+
+ camel_session_submit_job (
+ session, (CamelSessionCallback)
+ vee_store_rebuild_unmatched_folder,
+ g_object_ref (vstore),
+ g_object_unref);
+ } else {
+ vee_store_rebuild_unmatched_folder (NULL, cancellable, vstore, error);
+ }
+}
diff --git a/camel/camel-vee-store.h b/camel/camel-vee-store.h
index 890e2cf..69fdb5b 100644
--- a/camel/camel-vee-store.h
+++ b/camel/camel-vee-store.h
@@ -27,6 +27,7 @@
#define CAMEL_VEE_STORE_H
#include <camel/camel-store.h>
+#include <camel/camel-vee-data-cache.h>
/* Standard GObject macros */
#define CAMEL_TYPE_VEE_STORE \
@@ -50,32 +51,41 @@
G_BEGIN_DECLS
typedef struct _CamelVeeStore CamelVeeStore;
+typedef struct _CamelVeeStorePrivate CamelVeeStorePrivate;
typedef struct _CamelVeeStoreClass CamelVeeStoreClass;
-/* open mode for folder, vee folder auto-update */
-#define CAMEL_STORE_VEE_FOLDER_AUTO (1 << 16)
-
-/**
- * CAMEL_STORE_VEE_FOLDER_SPECIAL:
- *
- * Since: 2.24
- **/
-#define CAMEL_STORE_VEE_FOLDER_SPECIAL (1 << 17)
-
struct _CamelVeeStore {
CamelStore parent;
- /* Unmatched folder, set up in camel_vee_store_init */
- struct _CamelVeeFolder *folder_unmatched;
- GHashTable *unmatched_uids;
+ CamelVeeStorePrivate *priv;
};
struct _CamelVeeStoreClass {
CamelStoreClass parent_class;
};
-GType camel_vee_store_get_type (void);
-CamelVeeStore * camel_vee_store_new (void);
+GType camel_vee_store_get_type (void);
+CamelVeeStore * camel_vee_store_new (void);
+CamelVeeDataCache * camel_vee_store_get_vee_data_cache (CamelVeeStore *vstore);
+struct _CamelVeeFolder *camel_vee_store_get_unmatched_folder (CamelVeeStore *vstore);
+gboolean camel_vee_store_get_unmatched_enabled (CamelVeeStore *vstore);
+void camel_vee_store_set_unmatched_enabled (CamelVeeStore *vstore,
+ gboolean is_enabled);
+void camel_vee_store_note_subfolder_used (CamelVeeStore *vstore,
+ CamelFolder *subfolder,
+ struct _CamelVeeFolder *used_by);
+void camel_vee_store_note_subfolder_unused (CamelVeeStore *vstore,
+ CamelFolder *subfolder,
+ struct _CamelVeeFolder *unused_by);
+void camel_vee_store_note_vuid_used (CamelVeeStore *vstore,
+ CamelVeeMessageInfoData *mi_data,
+ struct _CamelVeeFolder *used_by);
+void camel_vee_store_note_vuid_unused (CamelVeeStore *vstore,
+ CamelVeeMessageInfoData *mi_data,
+ struct _CamelVeeFolder *unused_by);
+void camel_vee_store_rebuild_unmatched_folder (CamelVeeStore *vstore,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/camel/camel-vee-summary.c b/camel/camel-vee-summary.c
index e638ed7..b9a7a11 100644
--- a/camel/camel-vee-summary.c
+++ b/camel/camel-vee-summary.c
@@ -41,6 +41,11 @@
#define d(x)
+struct _CamelVeeSummaryPrivate
+{
+ GHashTable *vuids_by_subfolder; /* CamelFolder * => GHashTable * of gchar *vuid */
+};
+
G_DEFINE_TYPE (CamelVeeSummary, camel_vee_summary, CAMEL_TYPE_FOLDER_SUMMARY)
static void
@@ -49,8 +54,9 @@ vee_message_info_free (CamelFolderSummary *s,
{
CamelVeeMessageInfo *mi = (CamelVeeMessageInfo *) info;
- camel_pstring_free (info->uid);
g_object_unref (mi->orig_summary);
+
+ CAMEL_FOLDER_SUMMARY_CLASS (camel_vee_summary_parent_class)->message_info_free (s, info);
}
static CamelMessageInfo *
@@ -144,6 +150,22 @@ vee_info_user_tag (const CamelMessageInfo *mi,
return ret;
}
+static void
+vee_summary_notify_mi_changed (CamelVeeFolder *vfolder,
+ CamelMessageInfo *mi)
+{
+ CamelFolderChangeInfo *changes;
+
+ g_return_if_fail (vfolder != NULL);
+ g_return_if_fail (mi != NULL);
+
+ changes = camel_folder_change_info_new ();
+
+ camel_folder_change_info_change_uid (changes, camel_message_info_uid (mi));
+ camel_folder_changed (CAMEL_FOLDER (vfolder), changes);
+ camel_folder_change_info_free (changes);
+}
+
static gboolean
vee_info_set_user_flag (CamelMessageInfo *mi,
const gchar *name,
@@ -152,25 +174,23 @@ vee_info_set_user_flag (CamelMessageInfo *mi,
gint res = FALSE;
CamelVeeFolder *vf = (CamelVeeFolder *) camel_folder_summary_get_folder (mi->summary);
- if (camel_debug("vfolderexp"))
- printf (
- "Expression for vfolder '%s' is '%s'\n",
- camel_folder_get_full_name (camel_folder_summary_get_folder (mi->summary)),
- g_strescape (vf->expression, ""));
-
if (mi->uid) {
CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid + 8);
+ gboolean ignore_changes = !CAMEL_IS_VTRASH_FOLDER (vf);
HANDLE_NULL_INFO (FALSE);
/* ignore changes done in the folder itself,
* unless it's a vTrash or vJunk folder */
- if (!CAMEL_IS_VTRASH_FOLDER (vf))
+ if (ignore_changes)
camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder (rmi->summary));
res = camel_message_info_set_user_flag (rmi, name, value);
camel_message_info_free (rmi);
+
+ if (ignore_changes)
+ vee_summary_notify_mi_changed (vf, mi);
}
return res;
@@ -185,17 +205,21 @@ vee_info_set_user_tag (CamelMessageInfo *mi,
if (mi->uid) {
CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid + 8);
- CamelFolder *folder = camel_folder_summary_get_folder (mi->summary);
+ CamelVeeFolder *vf = (CamelVeeFolder *) camel_folder_summary_get_folder (mi->summary);
+ gboolean ignore_changes = !CAMEL_IS_VTRASH_FOLDER (vf);
HANDLE_NULL_INFO (FALSE);
/* ignore changes done in the folder itself,
* unless it's a vTrash or vJunk folder */
- if (!CAMEL_IS_VTRASH_FOLDER (folder))
- camel_vee_folder_ignore_next_changed_event ((CamelVeeFolder *) folder, camel_folder_summary_get_folder (rmi->summary));
+ if (ignore_changes)
+ camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder (rmi->summary));
res = camel_message_info_set_user_tag (rmi, name, value);
camel_message_info_free (rmi);
+
+ if (ignore_changes)
+ vee_summary_notify_mi_changed (vf, mi);
}
return res;
@@ -209,21 +233,16 @@ vee_info_set_flags (CamelMessageInfo *mi,
gint res = FALSE;
CamelVeeFolder *vf = CAMEL_VEE_FOLDER (camel_folder_summary_get_folder (mi->summary));
- if (camel_debug("vfolderexp"))
- printf (
- "Expression for vfolder '%s' is '%s'\n",
- camel_folder_get_full_name (CAMEL_FOLDER (vf)),
- g_strescape (vf->expression, ""));
-
/* first update original message info... */
if (mi->uid) {
CamelMessageInfo *rmi = camel_folder_summary_get (((CamelVeeMessageInfo *) mi)->orig_summary, mi->uid + 8);
+ gboolean ignore_changes = !CAMEL_IS_VTRASH_FOLDER (vf);
HANDLE_NULL_INFO (FALSE);
/* ignore changes done in the folder itself,
* unless it's a vTrash or vJunk folder */
- if (!CAMEL_IS_VTRASH_FOLDER (vf))
+ if (ignore_changes)
camel_vee_folder_ignore_next_changed_event (vf, camel_folder_summary_get_folder (rmi->summary));
camel_folder_freeze (camel_folder_summary_get_folder (rmi->summary));
@@ -231,11 +250,24 @@ vee_info_set_flags (CamelMessageInfo *mi,
((CamelVeeMessageInfo *) mi)->old_flags = camel_message_info_flags (rmi);
camel_folder_thaw (camel_folder_summary_get_folder (rmi->summary));
+ if (res) {
+ /* update flags on itself too */
+ camel_folder_summary_replace_flags (mi->summary, mi);
+ }
+
camel_message_info_free (rmi);
+
+ if (ignore_changes)
+ vee_summary_notify_mi_changed (vf, mi);
}
- if (res)
- CAMEL_FOLDER_SUMMARY_CLASS (camel_vee_summary_parent_class)->info_set_flags (mi, flags, set);
+ /* Do not call parent class' info_set_flags, to not do flood
+ of change notifications, rather wait for a notification
+ from original folder, and propagate the change in counts
+ through camel_vee_summary_replace_flags().
+ */
+ /*if (res)
+ CAMEL_FOLDER_SUMMARY_CLASS (camel_vee_summary_parent_class)->info_set_flags (mi, flags, set);*/
return res;
}
@@ -249,7 +281,7 @@ message_info_from_uid (CamelFolderSummary *s,
info = camel_folder_summary_peek_loaded (s, uid);
if (!info) {
CamelVeeMessageInfo *vinfo;
- gchar tmphash[9];
+ CamelFolder *orig_folder;
/* This function isn't really nice. But no great way
* But in vfolder case, this may not be so bad, as vuid has the hash in first 8 bytes.
@@ -264,14 +296,19 @@ message_info_from_uid (CamelFolderSummary *s,
/* Create the info and load it, its so easy. */
info = camel_message_info_new (s);
- camel_message_info_ref (info);
info->dirty = FALSE;
- vinfo = (CamelVeeMessageInfo *) info;
info->uid = camel_pstring_strdup (uid);
- strncpy (tmphash, uid, 8);
- tmphash[8] = 0;
- vinfo->orig_summary = g_hash_table_lookup (((CamelVeeFolder *) camel_folder_summary_get_folder (s))->hashes, tmphash);
+
+ orig_folder = camel_vee_folder_get_vee_uid_folder (
+ (CamelVeeFolder *) camel_folder_summary_get_folder (s), uid);
+ g_return_val_if_fail (orig_folder != NULL, NULL);
+
+ vinfo = (CamelVeeMessageInfo *) info;
+ vinfo->orig_summary = orig_folder->summary;
+
g_object_ref (vinfo->orig_summary);
+ camel_message_info_ref (info);
+
camel_folder_summary_insert (s, info, FALSE);
}
@@ -279,10 +316,27 @@ message_info_from_uid (CamelFolderSummary *s,
}
static void
+vee_summary_finalize (GObject *object)
+{
+ CamelVeeSummary *vsummary = CAMEL_VEE_SUMMARY (object);
+
+ g_hash_table_destroy (vsummary->priv->vuids_by_subfolder);
+
+ /* Chain up to parent's finalize() method. */
+ G_OBJECT_CLASS (camel_vee_summary_parent_class)->finalize (object);
+}
+
+static void
camel_vee_summary_class_init (CamelVeeSummaryClass *class)
{
+ GObjectClass *object_class;
CamelFolderSummaryClass *folder_summary_class;
+ g_type_class_add_private (class, sizeof (CamelVeeSummaryPrivate));
+
+ object_class = G_OBJECT_CLASS (class);
+ object_class->finalize = vee_summary_finalize;
+
folder_summary_class = CAMEL_FOLDER_SUMMARY_CLASS (class);
folder_summary_class->message_info_size = sizeof (CamelVeeMessageInfo);
folder_summary_class->content_info_size = 0;
@@ -302,6 +356,11 @@ camel_vee_summary_class_init (CamelVeeSummaryClass *class)
static void
camel_vee_summary_init (CamelVeeSummary *vee_summary)
{
+ vee_summary->priv = G_TYPE_INSTANCE_GET_PRIVATE (vee_summary,
+ CAMEL_TYPE_VEE_SUMMARY, CamelVeeSummaryPrivate);
+
+ vee_summary->priv->vuids_by_subfolder =
+ g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) g_hash_table_destroy);
}
/**
@@ -316,81 +375,171 @@ camel_vee_summary_init (CamelVeeSummary *vee_summary)
CamelFolderSummary *
camel_vee_summary_new (CamelFolder *parent)
{
- CamelVeeSummary *s;
+ CamelFolderSummary *summary;
CamelStore *parent_store;
const gchar *full_name;
- s = g_object_new (CAMEL_TYPE_VEE_SUMMARY, "folder", parent, NULL);
+ summary = g_object_new (CAMEL_TYPE_VEE_SUMMARY, "folder", parent, NULL);
+ summary->flags |= CAMEL_FOLDER_SUMMARY_IN_MEMORY_ONLY;
+ /* not using DB for vee folder summaries, drop the table */
full_name = camel_folder_get_full_name (parent);
parent_store = camel_folder_get_parent_store (parent);
- camel_db_create_vfolder (parent_store->cdb_w, full_name, NULL);
+ camel_db_delete_folder (parent_store->cdb_w, full_name, NULL);
- return (CamelFolderSummary *) s;
+ return summary;
}
-/**
- * camel_vee_summary_get_ids:
- *
- * Since: 2.24
- **/
-GPtrArray *
-camel_vee_summary_get_ids (CamelVeeSummary *summary,
- gchar hash[8])
+static void
+get_uids_for_subfolder (gpointer key,
+ gpointer value,
+ gpointer user_data)
{
- gchar *shash = g_strdup_printf("%c%c%c%c%c%c%c%c", hash[0], hash[1], hash[2], hash[3], hash[4], hash[5], hash[6], hash[7]);
- CamelFolderSummary *cfs = (CamelFolderSummary *) summary;
- CamelStore *parent_store;
- GPtrArray *array;
- const gchar *full_name;
+ g_hash_table_insert (user_data, (gpointer) camel_pstring_strdup (key), GINT_TO_POINTER (1));
+}
+
+GHashTable *
+camel_vee_summary_get_uids_for_subfolder (CamelVeeSummary *summary,
+ CamelFolder *subfolder)
+{
+ GHashTable *vuids, *known_uids;
- /* FIXME[disk-summary] fix exception passing */
- full_name = camel_folder_get_full_name (camel_folder_summary_get_folder (cfs));
- parent_store = camel_folder_get_parent_store (camel_folder_summary_get_folder (cfs));
- array = camel_db_get_vuids_from_vfolder (parent_store->cdb_r, full_name, shash, NULL);
+ g_return_val_if_fail (CAMEL_IS_VEE_SUMMARY (summary), NULL);
+ g_return_val_if_fail (CAMEL_IS_FOLDER (subfolder), NULL);
- g_free (shash);
+ camel_folder_summary_lock (&summary->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
- return array;
+ /* uses direct hash, because strings are supposed to be from the string pool */
+ known_uids = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) camel_pstring_free, NULL);
+
+ vuids = g_hash_table_lookup (summary->priv->vuids_by_subfolder, subfolder);
+ if (vuids) {
+ g_hash_table_foreach (vuids, get_uids_for_subfolder, known_uids);
+ }
+
+ camel_folder_summary_unlock (&summary->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ return known_uids;
}
+/* free returned pointer with camel_message_info_free() */
CamelVeeMessageInfo *
camel_vee_summary_add (CamelVeeSummary *s,
- CamelFolderSummary *summary,
- const gchar *uid,
- const gchar hash[8])
+ CamelVeeMessageInfoData *mi_data)
{
- CamelVeeMessageInfo *mi;
+ CamelVeeMessageInfo *vmi;
CamelMessageInfo *rmi;
- gchar *vuid;
- vuid = g_malloc (strlen (uid) + 9);
- memcpy (vuid, hash, 8);
- strcpy (vuid + 8, uid);
+ const gchar *uid, *vuid;
+ CamelVeeSubfolderData *sf_data;
+ CamelFolder *orig_folder;
+ GHashTable *vuids;
+
+ g_return_val_if_fail (CAMEL_IS_VEE_SUMMARY (s), NULL);
+ g_return_val_if_fail (CAMEL_IS_VEE_MESSAGE_INFO_DATA (mi_data), NULL);
- mi = (CamelVeeMessageInfo *) camel_folder_summary_peek_loaded (&s->summary, vuid);
- if (mi) {
+ camel_folder_summary_lock (&s->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ sf_data = camel_vee_message_info_data_get_subfolder_data (mi_data);
+ uid = camel_vee_message_info_data_get_orig_message_uid (mi_data);
+ vuid = camel_vee_message_info_data_get_vee_message_uid (mi_data);
+ orig_folder = camel_vee_subfolder_data_get_folder (sf_data);
+
+ vmi = (CamelVeeMessageInfo *) camel_folder_summary_peek_loaded (&s->summary, vuid);
+ if (vmi) {
/* Possible that the entry is loaded, see if it has the summary */
d(g_message ("%s - already there\n", vuid));
- g_free (vuid);
- if (!mi->orig_summary)
- mi->orig_summary = g_object_ref (summary);
- return mi;
+ if (!vmi->orig_summary)
+ vmi->orig_summary = g_object_ref (orig_folder->summary);
+
+ camel_folder_summary_unlock (&s->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ return vmi;
}
- mi = (CamelVeeMessageInfo *) camel_message_info_new (&s->summary);
- mi->orig_summary = g_object_ref (summary);
- mi->info.uid = (gchar *) camel_pstring_strdup (vuid);
- g_free (vuid);
- camel_message_info_ref (mi);
+ vmi = (CamelVeeMessageInfo *) camel_message_info_new (&s->summary);
+ vmi->orig_summary = g_object_ref (orig_folder->summary);
+ vmi->info.uid = (gchar *) camel_pstring_strdup (vuid);
+
+ camel_message_info_ref (vmi);
/* Get actual flags and store it */
- rmi = camel_folder_summary_get (summary, uid);
+ rmi = camel_folder_summary_get (orig_folder->summary, uid);
if (rmi) {
- mi->old_flags = camel_message_info_flags (rmi);
+ vmi->old_flags = camel_message_info_flags (rmi);
camel_message_info_free (rmi);
}
- camel_folder_summary_insert (&s->summary, (CamelMessageInfo *) mi, FALSE);
+ vuids = g_hash_table_lookup (s->priv->vuids_by_subfolder, orig_folder);
+ if (vuids) {
+ g_hash_table_insert (vuids, (gpointer) camel_pstring_strdup (vuid), GINT_TO_POINTER (1));
+ } else {
+ vuids = g_hash_table_new_full (g_direct_hash, g_direct_equal, (GDestroyNotify) camel_pstring_free, NULL);
+ g_hash_table_insert (vuids, (gpointer) camel_pstring_strdup (vuid), GINT_TO_POINTER (1));
+ g_hash_table_insert (s->priv->vuids_by_subfolder, orig_folder, vuids);
+ }
+
+ camel_folder_summary_insert (&s->summary, (CamelMessageInfo *) vmi, FALSE);
+ camel_folder_summary_unlock (&s->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ return vmi;
+}
+
+void
+camel_vee_summary_remove (CamelVeeSummary *summary,
+ const gchar *vuid,
+ CamelFolder *subfolder)
+{
+ GHashTable *vuids;
+
+ g_return_if_fail (CAMEL_IS_VEE_SUMMARY (summary));
+ g_return_if_fail (vuid != NULL);
+ g_return_if_fail (subfolder != NULL);
+
+ camel_folder_summary_lock (&summary->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ vuids = g_hash_table_lookup (summary->priv->vuids_by_subfolder, subfolder);
+ if (vuids) {
+ g_hash_table_remove (vuids, vuid);
+ if (!g_hash_table_size (vuids))
+ g_hash_table_remove (summary->priv->vuids_by_subfolder, subfolder);
+ }
+ camel_folder_summary_remove_uid (&summary->summary, vuid);
+
+ camel_folder_summary_unlock (&summary->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+}
+
+/**
+ * camel_vee_summary_replace_flags:
+ * @summary: a #CamelVeeSummary
+ * @uid: a message UID to update flags for
+ *
+ * Makes sure @summary flags on @uid corresponds to those
+ * in the subfolder of vee-folder, and updates internal counts
+ * on @summary as well.
+ **/
+void
+camel_vee_summary_replace_flags (CamelVeeSummary *summary,
+ const gchar *uid)
+{
+ CamelMessageInfo *mi;
+ CamelVeeMessageInfo *vmi;
+
+ g_return_if_fail (CAMEL_IS_VEE_SUMMARY (summary));
+ g_return_if_fail (uid != NULL);
+
+ camel_folder_summary_lock (&summary->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+
+ mi = camel_folder_summary_get (&summary->summary, uid);
+ if (!mi) {
+ camel_folder_summary_unlock (&summary->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
+ return;
+ }
+
+ vmi = (CamelVeeMessageInfo *) mi;
+ vmi->old_flags = camel_message_info_flags (mi);
+
+ camel_folder_summary_replace_flags (&summary->summary, mi);
+ camel_message_info_free (mi);
- return mi;
+ camel_folder_summary_unlock (&summary->summary, CAMEL_FOLDER_SUMMARY_SUMMARY_LOCK);
}
diff --git a/camel/camel-vee-summary.h b/camel/camel-vee-summary.h
index 2667e7a..4b866ea 100644
--- a/camel/camel-vee-summary.h
+++ b/camel/camel-vee-summary.h
@@ -50,11 +50,13 @@
G_BEGIN_DECLS
+struct _CamelVeeMessageInfoData;
struct _CamelVeeFolder;
struct _CamelFolder;
typedef struct _CamelVeeSummary CamelVeeSummary;
typedef struct _CamelVeeSummaryClass CamelVeeSummaryClass;
+typedef struct _CamelVeeSummaryPrivate CamelVeeSummaryPrivate;
typedef struct _CamelVeeMessageInfo CamelVeeMessageInfo;
@@ -66,6 +68,8 @@ struct _CamelVeeMessageInfo {
struct _CamelVeeSummary {
CamelFolderSummary summary;
+
+ CamelVeeSummaryPrivate *priv;
};
struct _CamelVeeSummaryClass {
@@ -77,11 +81,15 @@ CamelFolderSummary *
camel_vee_summary_new (struct _CamelFolder *parent);
CamelVeeMessageInfo *
camel_vee_summary_add (CamelVeeSummary *s,
- CamelFolderSummary *summary,
- const gchar *uid,
- const gchar hash[8]);
-GPtrArray * camel_vee_summary_get_ids (CamelVeeSummary *summary,
- gchar hash[8]);
+ struct _CamelVeeMessageInfoData *mi_data);
+void camel_vee_summary_remove (CamelVeeSummary *summary,
+ const gchar *vuid,
+ CamelFolder *subfolder);
+void camel_vee_summary_replace_flags (CamelVeeSummary *summary,
+ const gchar *uid);
+GHashTable * camel_vee_summary_get_uids_for_subfolder
+ (CamelVeeSummary *summary,
+ CamelFolder *subfolder);
G_END_DECLS
diff --git a/camel/camel-vtrash-folder.c b/camel/camel-vtrash-folder.c
index fff4a39..223eb57 100644
--- a/camel/camel-vtrash-folder.c
+++ b/camel/camel-vtrash-folder.c
@@ -260,9 +260,7 @@ camel_vtrash_folder_new (CamelStore *parent_store,
camel_vee_folder_construct (
CAMEL_VEE_FOLDER (vtrash),
CAMEL_STORE_FOLDER_PRIVATE |
- CAMEL_STORE_FOLDER_CREATE |
- CAMEL_STORE_VEE_FOLDER_AUTO |
- CAMEL_STORE_VEE_FOLDER_SPECIAL);
+ CAMEL_STORE_FOLDER_CREATE);
((CamelFolder *) vtrash)->folder_flags |= vdata[type].flags;
camel_vee_folder_set_expression ((CamelVeeFolder *) vtrash, vdata[type].expr);
diff --git a/camel/camel.h b/camel/camel.h
index e21246f..ceec583 100644
--- a/camel/camel.h
+++ b/camel/camel.h
@@ -137,6 +137,7 @@
#include <camel/camel-url.h>
#include <camel/camel-url-scanner.h>
#include <camel/camel-utf8.h>
+#include <camel/camel-vee-data-cache.h>
#include <camel/camel-vee-folder.h>
#include <camel/camel-vee-store.h>
#include <camel/camel-vee-summary.h>
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index ee3f5e6..9570fd7 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -1505,7 +1505,7 @@ imap_sync_offline (CamelFolder *folder,
parent_store = camel_folder_get_parent_store (folder);
- if (folder->summary && (folder->summary->flags & CAMEL_SUMMARY_DIRTY) != 0) {
+ if (folder->summary && (folder->summary->flags & CAMEL_FOLDER_SUMMARY_DIRTY) != 0) {
CamelStoreInfo *si;
const gchar *full_name;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]