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
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;
}
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
/* 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. */
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;
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);
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 *
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 *
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
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);
}
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);
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
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
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;
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);
}
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;
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;
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
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
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));
+ }
}
/**
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, '/');
}
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
CamelFolder *foldercopy,
CamelVeeFolder *vf)
{
- camel_vee_folder_remove_folder (vf, folder);
+ camel_vee_folder_remove_folder (vf, folder, NULL);
g_object_unref (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);
}
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);
}
/**
{
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
}
}
+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,
* 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);
}
/**
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 ();
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 ();