summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMilan Crha <mcrha@redhat.com>2011-08-23 13:20:19 +0200
committerMilan Crha <mcrha@redhat.com>2011-08-23 13:20:19 +0200
commit4de215d8a23a1e5486daa5f8d65671f5e7b0193b (patch)
treeb58d1dc5f9e352489e4a7734f9257b0be22ec49b
parent6c995c5a3290225f5db7c140872c0d0198bc8bd7 (diff)
downloadevolution-data-server-4de215d8a23a1e5486daa5f8d65671f5e7b0193b.tar.gz
Bug #562912 - Unread vfolder marks unread messages as read
-rw-r--r--camel/camel-vee-folder.c118
-rw-r--r--camel/camel-vee-folder.h1
-rw-r--r--camel/camel-vee-summary.c103
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);
}