aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/vee/camel-vee-folder.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/vee/camel-vee-folder.c')
-rw-r--r--camel/providers/vee/camel-vee-folder.c228
1 files changed, 201 insertions, 27 deletions
diff --git a/camel/providers/vee/camel-vee-folder.c b/camel/providers/vee/camel-vee-folder.c
index da47761754..77c3017179 100644
--- a/camel/providers/vee/camel-vee-folder.c
+++ b/camel/providers/vee/camel-vee-folder.c
@@ -24,6 +24,9 @@
#include "camel-vee-folder.h"
#include "camel-folder-summary.h"
#include "camel-mime-message.h"
+#ifdef DYNAMIC
+#include "camel-folder-search.h"
+#endif
#include <string.h>
@@ -128,6 +131,11 @@ camel_vee_folder_init (CamelVeeFolder *obj)
CAMEL_MESSAGE_DRAFT |
CAMEL_MESSAGE_FLAGGED |
CAMEL_MESSAGE_SEEN;
+
+ obj->changes = camel_folder_change_info_new();
+#ifdef DYNAMIC
+ obj->search = camel_folder_search_new();
+#endif
}
static void
@@ -137,12 +145,19 @@ camel_vee_folder_finalise (CamelObject *obj)
struct _CamelVeeFolderPrivate *p = _PRIVATE(vf);
GList *node;
+ /* FIXME: some leaks here, summary etc */
+
node = p->folders;
while (node) {
CamelFolder *f = node->data;
camel_object_unref((CamelObject *)f);
node = g_list_next(node);
}
+
+ camel_folder_change_info_free(vf->changes);
+#ifdef DYNAMIC
+ camel_object_unref((CamelObject *)vf->search);
+#endif
}
/**
@@ -156,8 +171,7 @@ camel_vee_folder_finalise (CamelObject *obj)
* Return value: A new CamelVeeFolder widget.
**/
CamelFolder *
-camel_vee_folder_new (CamelStore *parent_store, const char *name,
- CamelException *ex)
+camel_vee_folder_new (CamelStore *parent_store, const char *name, CamelException *ex)
{
CamelFolder *folder;
CamelVeeFolder *vf;
@@ -192,16 +206,136 @@ camel_vee_folder_new (CamelStore *parent_store, const char *name,
return folder;
}
+#ifdef DYNAMIC
+static void
+vfolder_remove_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo)
+{
+ printf("removing match %s\n", vinfo->info.uid);
+
+ g_hash_table_remove(vf->messages_uid, vinfo->info.uid);
+ g_ptr_array_remove_fast(vf->messages, vinfo);
+ camel_folder_change_info_remove_uid(vf->changes, vinfo->info.uid);
+ camel_message_info_free((CamelMessageInfo *)vinfo);
+}
+
+static CamelVeeMessageInfo *
+vfolder_add_match(CamelVeeFolder *vf, CamelFolder *f, const CamelMessageInfo *info)
+{
+ CamelVeeMessageInfo *mi;
+
+ mi = g_malloc0(sizeof(*mi));
+ camel_message_info_dup_to(info, (CamelMessageInfo*)mi);
+ g_free (mi->info.uid);
+ mi->info.uid = g_strdup_printf("%p:%s", f, info->uid);
+ mi->folder = f;
+ g_ptr_array_add(vf->messages, mi);
+ g_hash_table_insert(vf->messages_uid, mi->info.uid, mi);
+
+ printf("adding match %s\n", mi->info.uid);
+
+ camel_folder_change_info_add_uid(vf->changes, mi->info.uid);
+ return mi;
+}
+#endif
+
+static void
+vfolder_change_match(CamelVeeFolder *vf, CamelVeeMessageInfo *vinfo, const CamelMessageInfo *info)
+{
+ CamelFlag *flag;
+ CamelTag *tag;
+
+ printf("changing match %s\n", vinfo->info.uid);
+
+ vinfo->info.flags = info->flags;
+ camel_flag_list_free(&vinfo->info.user_flags);
+ flag = info->user_flags;
+ while (flag) {
+ camel_flag_set(&vinfo->info.user_flags, flag->name, TRUE);
+ flag = flag->next;
+ }
+ camel_tag_list_free(&vinfo->info.user_tags);
+ tag = info->user_tags;
+ while (tag) {
+ camel_tag_set(&vinfo->info.user_tags, tag->name, tag->value);
+ tag = tag->next;
+ }
+ camel_folder_change_info_change_uid(vf->changes, vinfo->info.uid);
+}
+
static void
folder_changed(CamelFolder *sub, gpointer type, CamelVeeFolder *vf)
{
CamelException *ex;
- ex = camel_exception_new();
- vee_folder_build_folder(vf, sub, ex);
- camel_exception_free(ex);
- /* FIXME: should only raise follow-on event if the result changed */
- camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", GINT_TO_POINTER(0));
+#ifdef DYNAMIC
+ CamelFolderChangeInfo *changes = type;
+
+ /* assume its faster to search a long list in whole, than by part */
+ if (changes && (changes->uid_added->len + changes->uid_changed->len) < 500) {
+ int i;
+ char *vuid;
+ CamelVeeMessageInfo *vinfo;
+ gboolean match;
+ const CamelMessageInfo *info;
+
+ ex = camel_exception_new();
+
+ /* see if added ones now match us */
+ for (i=0;i<changes->uid_added->len;i++) {
+ info = camel_folder_get_message_info(sub, changes->uid_added->pdata[i]);
+ if (info) {
+ camel_folder_search_set_folder(vf->search, sub);
+ match = camel_folder_search_match_expression(vf->search, vf->expression, info, ex);
+ if (match)
+ vinfo = vfolder_add_match(vf, sub, info);
+ }
+ }
+
+ /* check if changed ones still match */
+ for (i=0;i<changes->uid_changed->len;i++) {
+ info = camel_folder_get_message_info(sub, changes->uid_changed->pdata[i]);
+ vuid = g_strdup_printf("%p:%s", sub, (char *)changes->uid_changed->pdata[i]);
+ vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)vf, vuid);
+ if (info) {
+ camel_folder_search_set_folder(vf->search, sub);
+ match = camel_folder_search_match_expression(vf->search, vf->expression, info, ex);
+ if (vinfo) {
+ if (match)
+ vfolder_change_match(vf, vinfo, info);
+ else
+ vfolder_remove_match(vf, vinfo);
+ } else if (match)
+ vfolder_add_match(vf, sub, info);
+ } else if (vinfo)
+ vfolder_remove_match(vf, vinfo);
+
+ g_free(vuid);
+ }
+
+ camel_exception_free(ex);
+
+ /* mirror removes directly, if they used to match */
+ for (i=0;i<changes->uid_removed->len;i++) {
+ vuid = g_strdup_printf("%p:%s", sub, (char *)changes->uid_removed->pdata[i]);
+ vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)vf, vuid);
+ if (vinfo)
+ vfolder_remove_match(vf, vinfo);
+ g_free(vuid);
+ }
+ } else {
+#endif
+ ex = camel_exception_new();
+ vee_folder_build_folder(vf, sub, ex);
+ camel_exception_free(ex);
+#ifdef DYNAMIC
+ }
+#endif
+
+ /* cascade up, if we need to */
+ if (camel_folder_change_info_changed(vf->changes)) {
+ camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", vf->changes);
+ camel_folder_change_info_clear(vf->changes);
+ }
}
/* track flag changes in the summary */
@@ -209,24 +343,49 @@ static void
message_changed(CamelFolder *f, const char *uid, CamelVeeFolder *mf)
{
const CamelMessageInfo *info;
- CamelMessageInfo *vinfo;
- CamelFlag *flag;
+ CamelVeeMessageInfo *vinfo;
char *vuid;
+#ifdef DYNAMIC
+ gboolean match;
+ CamelException *ex;
+#endif
info = camel_folder_get_message_info(f, uid);
-
vuid = g_strdup_printf("%p:%s", f, uid);
- vinfo = (CamelMessageInfo *)vee_get_message_info((CamelFolder *)mf, vuid);
- if (info && vinfo) {
- vinfo->flags = info->flags;
- camel_flag_list_free(&vinfo->user_flags);
- flag = info->user_flags;
- while (flag) {
- camel_flag_set(&vinfo->user_flags, flag->name, TRUE);
- flag = flag->next;
- }
- camel_object_trigger_event( CAMEL_OBJECT(mf), "message_changed", vinfo->uid);
+ vinfo = (CamelVeeMessageInfo *)vee_get_message_info((CamelFolder *)mf, vuid);
+
+ /* see if this message now matches/doesn't match anymore */
+
+ /* Hmm, this might not work if the folder uses some weird search thing,
+ and/or can be slow since it wont use any index index, hmmm. */
+
+#ifdef DYNAMIC
+ camel_folder_search_set_folder(mf->search, f);
+ ex = camel_exception_new();
+ match = camel_folder_search_match_expression(mf->search, mf->expression, info, ex);
+ camel_exception_free(ex);
+ if (info) {
+ if (vinfo) {
+ if (match)
+ vfolder_change_match(mf, vinfo, info);
+ else
+ vfolder_remove_match(mf, vinfo);
+ } else if (match)
+ vfolder_add_match(mf, f, info);
+ } else if (vinfo)
+ vfolder_remove_match(mf, vinfo);
+#else
+ if (info && vinfo)
+ vfolder_change_match(mf, vinfo, info);
+#endif
+
+ /* cascade up, if required. This could probably be delayed,
+ but doesn't matter really, that is what freeze is for. */
+ if (camel_folder_change_info_changed(mf->changes)) {
+ camel_object_trigger_event( CAMEL_OBJECT(mf), "folder_changed", mf->changes);
+ camel_folder_change_info_clear(mf->changes);
}
+
g_free(vuid);
}
@@ -245,8 +404,18 @@ camel_vee_folder_add_folder(CamelVeeFolder *vf, CamelFolder *sub)
ex = camel_exception_new();
vee_folder_build_folder(vf, sub, ex);
camel_exception_free(ex);
- /* FIXME: should only raise follow-on event if the result changed */
- camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", GINT_TO_POINTER(0));
+
+ /* we'll assume the caller is going to update the whole list after they do this
+ this may or may not be the right thing to do, but it should be close enough */
+#if 0
+ if (camel_folder_change_info_changed(vf->changes)) {
+ camel_object_trigger_event( CAMEL_OBJECT(vf), "folder_changed", vf->changes);
+ camel_folder_change_info_clear(vf->changes);
+ }
+#else
+ camel_folder_change_info_clear(vf->changes);
+#endif
+
}
@@ -441,6 +610,11 @@ vee_folder_build(CamelVeeFolder *vf, CamelException *ex)
messages = g_ptr_array_new();
messages_uid = g_hash_table_new(g_str_hash, g_str_equal);
+ g_ptr_array_free(vf->messages, TRUE);
+ vf->messages = messages;
+ g_hash_table_destroy(vf->messages_uid);
+ vf->messages_uid = messages_uid;
+
node = p->folders;
while (node) {
GPtrArray *matches;
@@ -465,11 +639,6 @@ vee_folder_build(CamelVeeFolder *vf, CamelException *ex)
camel_folder_search_free(f, matches);
node = g_list_next(node);
}
-
- g_ptr_array_free(vf->messages, TRUE);
- vf->messages = messages;
- g_hash_table_destroy(vf->messages_uid);
- vf->messages_uid = messages_uid;
}
@@ -489,6 +658,7 @@ vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException
for (i=0;i<vf->messages->len;i++) {
CamelVeeMessageInfo *mi = g_ptr_array_index(vf->messages, i);
if (mi->folder == source) {
+ camel_folder_change_info_add_source(vf->changes, mi->info.uid);
g_hash_table_remove(vf->messages_uid, mi->info.uid);
g_ptr_array_remove_index_fast(vf->messages, i);
@@ -511,9 +681,13 @@ vee_folder_build_folder(CamelVeeFolder *vf, CamelFolder *source, CamelException
mi->folder = f;
g_ptr_array_add(messages, mi);
g_hash_table_insert(messages_uid, mi->info.uid, mi);
+
+ camel_folder_change_info_add_update(vf->changes, mi->info.uid);
}
}
camel_folder_search_free(f, matches);
+
+ camel_folder_change_info_build_diff(vf->changes);
}