aboutsummaryrefslogtreecommitdiffstats
path: root/camel/camel-folder-search.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/camel-folder-search.c')
-rw-r--r--camel/camel-folder-search.c132
1 files changed, 91 insertions, 41 deletions
diff --git a/camel/camel-folder-search.c b/camel/camel-folder-search.c
index 993de40801..e0e5052a5f 100644
--- a/camel/camel-folder-search.c
+++ b/camel/camel-folder-search.c
@@ -275,7 +275,14 @@ camel_folder_search_set_folder(CamelFolderSearch *search, CamelFolder *folder)
void
camel_folder_search_set_summary(CamelFolderSearch *search, GPtrArray *summary)
{
+ int i;
+
search->summary = summary;
+ if (search->summary_hash)
+ g_hash_table_destroy(search->summary_hash);
+ search->summary_hash = g_hash_table_new(g_str_hash, g_str_equal);
+ for (i=0;i<summary->len;i++)
+ g_hash_table_insert(search->summary_hash, (char *)camel_message_info_uid(summary->pdata[i]), summary->pdata[i]);
}
/**
@@ -283,15 +290,19 @@ camel_folder_search_set_summary(CamelFolderSearch *search, GPtrArray *summary)
* @search:
* @index:
*
- * Set the index (ibex) representing the contents of all messages
+ * Set the index representing the contents of all messages
* in this folder. If this is not set, then the folder implementation
* should sub-class the CamelFolderSearch and provide its own
* body-contains function.
**/
void
-camel_folder_search_set_body_index(CamelFolderSearch *search, ibex *index)
+camel_folder_search_set_body_index(CamelFolderSearch *search, CamelIndex *index)
{
+ if (search->body_index)
+ camel_object_unref((CamelObject *)search->body_index);
search->body_index = index;
+ if (index)
+ camel_object_ref((CamelObject *)index);
}
/**
@@ -728,12 +739,79 @@ match_message(CamelFolder *folder, const char *uid, regex_t *pattern, CamelExcep
return truth;
}
+/* perform a regex match against words in an index */
+/* uids = hash table of messageinfo's by uid's */
+static GPtrArray *
+match_messages_index(CamelIndex *idx, regex_t *pattern, GHashTable *uids, CamelException *ex)
+{
+ GPtrArray *result = g_ptr_array_new();
+ GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
+ struct _glib_sux_donkeys lambdafoo;
+ CamelIndexCursor *wc, *nc;
+ const char *word, *name;
+ CamelMessageInfo *mi;
+
+ wc = camel_index_words(idx);
+ if (wc) {
+ while ((word = camel_index_cursor_next(wc))) {
+ if (regexec(pattern, word, 0, NULL, 0) == 0) {
+ /* perf: could have the wc cursor return the name cursor */
+ nc = camel_index_find(idx, word);
+ if (nc) {
+ while ((name = camel_index_cursor_next(nc))) {
+ mi = g_hash_table_lookup(uids, name);
+ if (mi)
+ g_hash_table_insert(ht, (char *)camel_message_info_uid(mi), (void *)1);
+ }
+ camel_object_unref((CamelObject *)nc);
+ }
+ }
+ }
+ camel_object_unref((CamelObject *)wc);
+
+ lambdafoo.uids = result;
+ g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
+ g_hash_table_destroy(ht);
+ }
+
+ return result;
+}
+
+/* perform a regex match against an individual uid in an index */
+/* this would benefit greatly in practice if there was a hashtalbe of uid's to amtch against */
+static int
+match_message_index(CamelIndex *idx, const char *uid, regex_t *pattern, CamelException *ex)
+{
+ CamelIndexCursor *wc, *nc;
+ const char *word, *name;
+ int truth = FALSE;
+
+ wc = camel_index_words(idx);
+ if (wc) {
+ while (!truth && (word = camel_index_cursor_next(wc))) {
+ if (regexec(pattern, word, 0, NULL, 0) == 0) {
+ /* perf: could have the wc cursor return the name cursor */
+ nc = camel_index_find(idx, word);
+ if (nc) {
+ while (!truth && (name = camel_index_cursor_next(nc)))
+ truth = strcmp(name, uid) == 0;
+ camel_object_unref((CamelObject *)nc);
+ }
+ }
+ }
+ camel_object_unref((CamelObject *)wc);
+ }
+
+ return truth;
+}
+
static ESExpResult *
search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, CamelFolderSearch *search)
{
ESExpResult *r;
- int i, j;
+ int i;
regex_t pattern;
+ CamelException *ex = search->priv->ex;
if (search->current) {
int truth = FALSE;
@@ -741,19 +819,14 @@ search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, Cam
if (argc == 1 && argv[0]->value.string[0] == 0 && search->folder) {
truth = TRUE;
} else if (search->body_index) {
- for (i=0;i<argc && !truth;i++) {
- if (argv[i]->type == ESEXP_RES_STRING) {
- truth = ibex_find_name(search->body_index, (char *)camel_message_info_uid(search->current),
- argv[i]->value.string);
- } else {
- e_sexp_resultv_free(f, argc, argv);
- e_sexp_fatal_error(f, _("Invalid type in body-contains, expecting string"));
- }
+ if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, ex) == 0) {
+ truth = match_message_index(search->body_index, camel_message_info_uid(search->current), &pattern, ex);
+ regfree(&pattern);
}
} else if (search->folder) {
/* we do a 'slow' direct search */
- if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, search->priv->ex) == 0) {
- truth = match_message(search->folder, camel_message_info_uid(search->current), &pattern, search->priv->ex);
+ if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, ex) == 0) {
+ truth = match_message(search->folder, camel_message_info_uid(search->current), &pattern, ex);
regfree(&pattern);
}
} else {
@@ -772,42 +845,19 @@ search_body_contains(struct _ESExp *f, int argc, struct _ESExpResult **argv, Cam
g_ptr_array_add(r->value.ptrarray, (char *)camel_message_info_uid(info));
}
} else if (search->body_index) {
- if (argc==1) {
- /* common case */
- r->value.ptrarray = ibex_find(search->body_index, argv[0]->value.string);
- } else {
- GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
- GPtrArray *pa;
- struct _glib_sux_donkeys lambdafoo;
-
- /* this sux, perform an or operation on the result(s) of each word */
- for (i=0;i<argc;i++) {
- if (argv[i]->type == ESEXP_RES_STRING) {
- pa = ibex_find(search->body_index, argv[i]->value.string);
- for (j=0;j<pa->len;j++) {
- g_hash_table_insert(ht, g_ptr_array_index(pa, j), (void *)1);
- }
- g_ptr_array_free(pa, FALSE);
- } else {
- e_sexp_result_free(f, r);
- e_sexp_resultv_free(f, argc, argv);
- e_sexp_fatal_error(f, _("Invalid type in body-contains, expecting string"));
- }
- }
- lambdafoo.uids = g_ptr_array_new();
- g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
- r->value.ptrarray = lambdafoo.uids;
- g_hash_table_destroy(ht);
+ if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, ex) == 0) {
+ r->value.ptrarray = match_messages_index(search->body_index, &pattern, search->summary_hash, ex);
+ regfree(&pattern);
}
} else if (search->folder) {
/* do a slow search */
r->value.ptrarray = g_ptr_array_new();
- if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, search->priv->ex) == 0) {
+ if (camel_search_build_match_regex(&pattern, CAMEL_SEARCH_MATCH_ICASE, argc, argv, ex) == 0) {
if (search->summary) {
for (i=0;i<search->summary->len;i++) {
CamelMessageInfo *info = g_ptr_array_index(search->summary, i);
- if (match_message(search->folder, camel_message_info_uid(info), &pattern, search->priv->ex))
+ if (match_message(search->folder, camel_message_info_uid(info), &pattern, ex))
g_ptr_array_add(r->value.ptrarray, (char *)camel_message_info_uid(info));
}
} /* else? we could always get the summary from the folder, but then