diff options
author | Milan Crha <mcrha@redhat.com> | 2011-08-23 13:20:19 +0200 |
---|---|---|
committer | Milan Crha <mcrha@redhat.com> | 2011-08-23 13:20:19 +0200 |
commit | 4de215d8a23a1e5486daa5f8d65671f5e7b0193b (patch) | |
tree | b58d1dc5f9e352489e4a7734f9257b0be22ec49b | |
parent | 6c995c5a3290225f5db7c140872c0d0198bc8bd7 (diff) | |
download | evolution-data-server-4de215d8a23a1e5486daa5f8d65671f5e7b0193b.tar.gz |
Bug #562912 - Unread vfolder marks unread messages as read
-rw-r--r-- | camel/camel-vee-folder.c | 118 | ||||
-rw-r--r-- | camel/camel-vee-folder.h | 1 | ||||
-rw-r--r-- | camel/camel-vee-summary.c | 103 |
3 files changed, 130 insertions, 92 deletions
diff --git a/camel/camel-vee-folder.c b/camel/camel-vee-folder.c index d15f30f4b..cb90037f4 100644 --- a/camel/camel-vee-folder.c +++ b/camel/camel-vee-folder.c @@ -47,11 +47,12 @@ 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 */ + GHashTable *ignore_changed; /* hash of subfolder pointers to ignore the next folder's 'changed' signal */ + GHashTable *skipped_changes; /* CamelFolder -> CamelFolderChangeInfo accumulating ignored changes */ GMutex *summary_lock; /* for locking vfolder summary */ GMutex *subfolder_lock; /* for locking the subfolder list */ GMutex *changed_lock; /* for locking the folders-changed list */ - gint unread_vfolder; }; struct _update_data { @@ -847,6 +848,24 @@ folder_changed (CamelFolder *sub, { CamelVeeFolderClass *class; + 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); + class = CAMEL_VEE_FOLDER_GET_CLASS (vee_folder); class->folder_changed (vee_folder, sub, changes); } @@ -997,6 +1016,12 @@ vee_folder_dispose (GObject *object) } static void +free_change_info_cb (gpointer folder, gpointer change_info, gpointer user_data) +{ + camel_folder_change_info_free (change_info); +} + +static void vee_folder_finalize (GObject *object) { CamelVeeFolder *vf; @@ -1011,15 +1036,49 @@ vee_folder_finalize (GObject *object) camel_folder_change_info_free (vf->changes); g_object_unref (vf->search); + 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_hash_table_destroy (vf->priv->ignore_changed); + g_hash_table_destroy (vf->priv->skipped_changes); /* Chain up to parent's finalize () method. */ G_OBJECT_CLASS (camel_vee_folder_parent_class)->finalize (object); } +static void +vee_folder_propagate_skipped_changes (CamelVeeFolder *vf) +{ + CamelVeeFolderClass *klass; + GHashTableIter iter; + gpointer psub, pchanges; + + g_return_if_fail (vf != NULL); + + klass = CAMEL_VEE_FOLDER_GET_CLASS (vf); + + camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK); + + 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) + klass->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); +} + static GPtrArray * vee_folder_search_by_expression (CamelFolder *folder, const gchar *expression, @@ -1035,6 +1094,8 @@ vee_folder_search_by_expression (CamelFolder *folder, gboolean is_folder_unmatched = vf == folder_unmatched && folder_unmatched; GHashTable *folder_unmatched_hash = NULL; + vee_folder_propagate_skipped_changes (vf); + if (is_folder_unmatched) { expr = g_strdup (expression); folder_unmatched_hash = camel_folder_summary_get_hashtable (((CamelFolder *) folder_unmatched)->summary); @@ -1094,6 +1155,8 @@ vee_folder_search_by_uids (CamelFolder *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); expr = g_strdup_printf ("(and %s %s)", vf->expression ? vf->expression : "", expression); @@ -1157,6 +1220,8 @@ vee_folder_count_by_expression (CamelFolder *folder, 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 @@ -1313,6 +1378,8 @@ vee_folder_refresh_info_sync (CamelFolder *folder, GList *node, *list; gboolean success = TRUE; + vee_folder_propagate_skipped_changes (vf); + camel_vee_folder_lock (vf, CAMEL_VEE_FOLDER_CHANGED_LOCK); list = p->folders_changed; p->folders_changed = NULL; @@ -1345,6 +1412,8 @@ vee_folder_synchronize_sync (CamelFolder *folder, CamelVeeFolderPrivate *p = vf->priv; GList *node; + vee_folder_propagate_skipped_changes (vf); + if (((CamelVeeSummary *)folder->summary)->fake_visible_count) folder->summary->visible_count = ((CamelVeeSummary *)folder->summary)->fake_visible_count; ((CamelVeeSummary *)folder->summary)->fake_visible_count = 0; @@ -1377,7 +1446,7 @@ vee_folder_synchronize_sync (CamelFolder *folder, node = node->next; } - if (vf->priv->unread_vfolder == 1) { + if (!CAMEL_IS_VTRASH_FOLDER (vf)) { /* Cleanup Junk/Trash uids */ CamelStore *parent_store; const gchar *full_name; @@ -2032,7 +2101,8 @@ camel_vee_folder_init (CamelVeeFolder *vee_folder) vee_folder->priv->summary_lock = g_mutex_new (); vee_folder->priv->subfolder_lock = g_mutex_new (); vee_folder->priv->changed_lock = g_mutex_new (); - vee_folder->priv->unread_vfolder = -1; + 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); } void @@ -2262,6 +2332,8 @@ camel_vee_folder_rebuild_folder (CamelVeeFolder *vf, CamelFolder *sub, GError **error) { + vee_folder_propagate_skipped_changes (vf); + return CAMEL_VEE_FOLDER_GET_CLASS (vf)->rebuild_folder (vf, sub, error); } @@ -2401,24 +2473,52 @@ camel_vee_folder_get_location (CamelVeeFolder *vf, const CamelVeeMessageInfo *vi * camel_vee_folder_mask_event_folder_changed: * * Since: 2.26 + * + * Deprecated: 3.2: Does nothing, use camel_vee_folder_ignore_next_changed_event(). **/ void camel_vee_folder_mask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub) { - g_signal_handlers_block_by_func (sub, folder_changed, vf); } /** * camel_vee_folder_unmask_event_folder_changed: * * Since: 2.26 + * + * Deprecated: 3.2: Does nothing, use camel_vee_folder_ignore_next_changed_event(). **/ void camel_vee_folder_unmask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub) { - g_signal_handlers_unblock_by_func (sub, folder_changed, vf); +} + +/** + * camel_vee_folder_ignore_next_changed_event: + * @vf: a #CamelVeeFolder + * @sub: a #CamelFolder folder + * + * The next @sub folder'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, + * which could be done on asynchronous delivery of folder's 'changed' signal. + * These ignored changes are accumulated and used on folder refresh. + * + * 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); } /** @@ -2449,6 +2549,8 @@ camel_vee_folder_sync_headers (CamelFolder *vf, * @folder: a #CamelVeeFolder * * Since: 2.32 + * + * Deprecated: 3.2: Does nothing, returns always 0. **/ gint camel_vee_folder_get_unread_vfolder (CamelVeeFolder *folder) @@ -2456,7 +2558,7 @@ camel_vee_folder_get_unread_vfolder (CamelVeeFolder *folder) /* FIXME: This shouldn't be needed */ g_return_val_if_fail (CAMEL_IS_VEE_FOLDER (folder), 0); - return folder->priv->unread_vfolder; + return 0; } /** @@ -2465,6 +2567,8 @@ camel_vee_folder_get_unread_vfolder (CamelVeeFolder *folder) * @unread_vfolder: %TRUE if %folder is for unread messages * * Since: 2.32 + * + * Deprecated: 3.2: Does nothing. **/ void camel_vee_folder_set_unread_vfolder (CamelVeeFolder *folder, @@ -2472,8 +2576,6 @@ camel_vee_folder_set_unread_vfolder (CamelVeeFolder *folder, { /* FIXME: This shouldn't be needed */ g_return_if_fail (CAMEL_IS_VEE_FOLDER (folder)); - - folder->priv->unread_vfolder = unread_vfolder; } /** diff --git a/camel/camel-vee-folder.h b/camel/camel-vee-folder.h index 6909074c1..1b0843065 100644 --- a/camel/camel-vee-folder.h +++ b/camel/camel-vee-folder.h @@ -129,6 +129,7 @@ void camel_vee_folder_set_expression (CamelVeeFolder *vf, const gchar *expr void camel_vee_folder_mask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub); void camel_vee_folder_unmask_event_folder_changed (CamelVeeFolder *vf, CamelFolder *sub); +void camel_vee_folder_ignore_next_changed_event (CamelVeeFolder *vf, CamelFolder *sub); void camel_vee_folder_hash_folder (CamelFolder *folder, gchar buffer[8]); void camel_vee_folder_sync_headers (CamelFolder *vf, GError **error); diff --git a/camel/camel-vee-summary.c b/camel/camel-vee-summary.c index c34eddf46..2758c6e6a 100644 --- a/camel/camel-vee-summary.c +++ b/camel/camel-vee-summary.c @@ -36,12 +36,11 @@ #include "camel-vee-summary.h" #include "camel-vee-folder.h" #include "camel-vee-store.h" +#include "camel-vtrash-folder.h" #include "camel-string-utils.h" #define d(x) -static const gchar *unread_str = " (and\n \n (match-all (not (system-flag \"Seen\")))\n \n )\n; (or\n \n (match-all (not (system-flag \"Seen\")))\n \n )\n; (match-threads \"all\" (and\n \n (match-all (not (system-flag \"Seen\")))\n \n )\n)\n; (match-threads \"all\" (or\n \n (match-all (not (system-flag \"Seen\")))\n \n )\n)\n;"; - G_DEFINE_TYPE (CamelVeeSummary, camel_vee_summary, CAMEL_TYPE_FOLDER_SUMMARY) static void @@ -142,7 +141,6 @@ static gboolean vee_info_set_user_flag (CamelMessageInfo *mi, const gchar *name, gboolean value) { gint res = FALSE; - gboolean hacked_unread_folder = FALSE; CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder; if (camel_debug("vfolderexp")) @@ -151,24 +149,17 @@ vee_info_set_user_flag (CamelMessageInfo *mi, const gchar *name, gboolean value) camel_folder_get_full_name (mi->summary->folder), g_strescape (vf->expression, "")); - if (camel_vee_folder_get_unread_vfolder (vf) == -1) - camel_vee_summary_load_check_unread_vfolder (CAMEL_VEE_SUMMARY (mi->summary)); - - if (camel_vee_folder_get_unread_vfolder (vf) == 1) - hacked_unread_folder = TRUE; - if (mi->uid) { CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8); HANDLE_NULL_INFO (FALSE); - if (hacked_unread_folder) - camel_vee_folder_mask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder); + /* ignore changes done in the folder itself, + unless it's a vTrash or vJunk folder */ + if (!CAMEL_IS_VTRASH_FOLDER (vf)) + camel_vee_folder_ignore_next_changed_event (vf, rmi->summary->folder); res = camel_message_info_set_user_flag (rmi, name, value); - if (hacked_unread_folder) - camel_vee_folder_unmask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder); - camel_message_info_free (rmi); } @@ -183,6 +174,12 @@ vee_info_set_user_tag (CamelMessageInfo *mi, const gchar *name, const gchar *val if (mi->uid) { CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8); HANDLE_NULL_INFO (FALSE); + + /* ignore changes done in the folder itself, + unless it's a vTrash or vJunk folder */ + if (!CAMEL_IS_VTRASH_FOLDER (mi->summary->folder)) + camel_vee_folder_ignore_next_changed_event ((CamelVeeFolder *) mi->summary->folder, rmi->summary->folder); + res = camel_message_info_set_user_tag (rmi, name, value); camel_message_info_free (rmi); } @@ -194,37 +191,12 @@ vee_info_set_user_tag (CamelMessageInfo *mi, const gchar *name, const gchar *val * camel_vee_summary_load_check_unread_vfolder: * * Since: 2.26 + * + * Deprecated: 3.2: Does nothing. **/ void camel_vee_summary_load_check_unread_vfolder (CamelVeeSummary *vs) { - static gint only_once = FALSE; - static gchar *exp = NULL; - gboolean hacked_unread_folder = FALSE; - CamelVeeFolder *vf; - - g_return_if_fail (vs != NULL); - - vf = (CamelVeeFolder *) ((CamelFolderSummary *)vs)->folder; - - /* HACK: Ugliest of all hacks. Its virtually not possible now - * to maintain counts and the non matching uids of unread vfolder here. - * So, I hardcode unread vfolder expression and hack it. */ - if (!only_once) { - exp = g_getenv("CAMEL_VFOLDER_UNREAD_EXP") ? g_strcompress(g_getenv("CAMEL_VFOLDER_UNREAD_EXP")) : NULL; - only_once = TRUE; - } - - if (!exp || !*exp) - exp = g_strcompress (unread_str); - - if (vf->expression && strstr (exp, vf->expression) && (vf->flags & CAMEL_STORE_VEE_FOLDER_SPECIAL) == 0) - hacked_unread_folder = TRUE; - - if (hacked_unread_folder) - camel_vee_folder_set_unread_vfolder (vf, 1); - else - camel_vee_folder_set_unread_vfolder (vf, 0); } static gboolean @@ -234,7 +206,6 @@ vee_info_set_flags (CamelMessageInfo *mi, { gint res = FALSE; CamelVeeFolder *vf = (CamelVeeFolder *)mi->summary->folder; - gboolean hacked_unread_folder = FALSE; if (camel_debug("vfolderexp")) printf ( @@ -242,68 +213,32 @@ vee_info_set_flags (CamelMessageInfo *mi, camel_folder_get_full_name (mi->summary->folder), g_strescape (vf->expression, "")); - if (camel_vee_folder_get_unread_vfolder (vf) == -1) - camel_vee_summary_load_check_unread_vfolder (CAMEL_VEE_SUMMARY (mi->summary)); - - if (camel_vee_folder_get_unread_vfolder (vf) == 1) - hacked_unread_folder = TRUE; - if (mi->uid) { - guint32 old_visible, visible, old_unread; CamelMessageInfo *rmi = camel_folder_summary_uid (((CamelVeeMessageInfo *)mi)->summary, mi->uid+8); - CamelVeeSummary *vsummary = (CamelVeeSummary *)mi->summary; HANDLE_NULL_INFO (FALSE); - old_visible = rmi->summary->visible_count; - old_unread = mi->summary->unread_count; camel_folder_summary_update_counts_by_flags (mi->summary, camel_message_info_flags (rmi), TRUE); - if (hacked_unread_folder) - camel_vee_folder_mask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder); + /* ignore changes done in the folder itself, + unless it's a vTrash or vJunk folder */ + if (!CAMEL_IS_VTRASH_FOLDER (vf)) + camel_vee_folder_ignore_next_changed_event (vf, rmi->summary->folder); camel_folder_freeze (rmi->summary->folder); res = camel_message_info_set_flags (rmi, flags, set); ((CamelVeeMessageInfo *) mi)->old_flags = camel_message_info_flags (rmi); camel_folder_thaw (rmi->summary->folder); - if (hacked_unread_folder) - camel_vee_folder_unmask_event_folder_changed ((CamelVeeFolder *)mi->summary->folder, rmi->summary->folder); - - visible = rmi->summary->visible_count; - /* Keep the summary in sync */ camel_folder_summary_update_counts_by_flags (mi->summary, camel_message_info_flags (rmi), FALSE); - if (hacked_unread_folder && !vsummary->fake_visible_count) - vsummary->fake_visible_count = mi->summary->visible_count; - - if (vsummary->fake_visible_count || hacked_unread_folder) - vsummary->fake_visible_count += visible - old_visible; - d(printf("VF %d %d %d %d %d\n", mi->summary->unread_count, mi->summary->deleted_count, mi->summary->junk_count, mi->summary->junk_not_deleted_count, mi->summary->visible_count)); - /* This is where the ugly-created-hack is used */ - if (hacked_unread_folder && mi->summary->unread_count - old_unread != 0) { + if (res && mi->summary && mi->summary->folder) { CamelFolderChangeInfo *changes = camel_folder_change_info_new (); - GPtrArray *match, *array; - - camel_folder_change_info_change_uid (changes, mi->uid); - - array = g_ptr_array_new (); - g_ptr_array_add (array, (gpointer)rmi->uid); - - match = camel_folder_search_by_uids (rmi->summary->folder, vf->expression, array, NULL); - if ((match && !match->len) || !match) { - vsummary->fake_visible_count--; - } else { - vsummary->fake_visible_count++; - } - - g_ptr_array_free (array, TRUE); - if (match) - camel_folder_search_free (rmi->summary->folder, match); + camel_folder_change_info_change_uid (changes, camel_message_info_uid (mi)); camel_folder_changed (mi->summary->folder, changes); camel_folder_change_info_free (changes); } |