aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/mbox/camel-mbox-search.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/mbox/camel-mbox-search.c')
-rw-r--r--camel/providers/mbox/camel-mbox-search.c873
1 files changed, 169 insertions, 704 deletions
diff --git a/camel/providers/mbox/camel-mbox-search.c b/camel/providers/mbox/camel-mbox-search.c
index 9648ae97ba..af9f820780 100644
--- a/camel/providers/mbox/camel-mbox-search.c
+++ b/camel/providers/mbox/camel-mbox-search.c
@@ -25,6 +25,7 @@
#include <time.h>
#include <string.h>
+
#include <camel/gmime-utils.h>
#include <camel/camel-log.h>
#include "camel/camel-folder-summary.h"
@@ -35,6 +36,9 @@
#include "camel/camel.h"
#include "camel-mbox-folder.h"
+#include "camel-mbox-search.h"
+#include "filter-sexp.h"
+
#define HAVE_IBEX
#ifdef HAVE_IBEX
#include "ibex.h"
@@ -47,37 +51,12 @@
/*
- This is not yet complete.
-
- The following s-exp's are supported:
-
- list = (and list*)
- perform an intersection of a number of lists, and return that.
-
- bool = (and bool*)
- perform a boolean AND of boolean values.
-
- list = (or list*)
- perform a union of a number of lists, returning the new list.
-
- bool = (or bool*)
- perform a boolean OR of boolean values.
-
- Comparison operators:
-
- bool = (lt int int)
- bool = (gt int int)
- bool = (eq int int)
-
- bool = (lt string string)
- bool = (gt string string)
- bool = (eq string string)
- Perform a comparision of 2 integers, or 2 string values.
-
Matching operators:
- list = (contains string)
- Returns a list of all messages containing the string in their body.
+ list = (body-contains string+)
+ bool = (body-contains string+)
+ Returns a list of all messages containing any of the strings in the message.
+ If within a match-all, then returns true for the current message.
list = (match-all bool-expr)
Returns a list of all messages for which the bool expression is true.
@@ -88,80 +67,11 @@
int = (date-sent)
Returns a time_t of the date-sent of the message.
- bool = (header-contains string1 string2)
+ bool = (header-contains string string+)
Returns true if the current message (inside a match-all operator)
- has a header 'string1', which contains 'string2'
+ has a header 'string1', which contains any of the following strings.
*/
-static GScannerConfig scanner_config =
-{
- (
- " \t\r\n"
- ) /* cset_skip_characters */,
- (
- G_CSET_a_2_z
- "_"
- G_CSET_A_2_Z
- ) /* cset_identifier_first */,
- (
- G_CSET_a_2_z
- "_0123456789-"
- G_CSET_A_2_Z
- G_CSET_LATINS
- G_CSET_LATINC
- ) /* cset_identifier_nth */,
- ( "#\n" ) /* cpair_comment_single */,
-
- FALSE /* case_sensitive */,
-
- TRUE /* skip_comment_multi */,
- TRUE /* skip_comment_single */,
- TRUE /* scan_comment_multi */,
- TRUE /* scan_identifier */,
- FALSE /* scan_identifier_1char */,
- FALSE /* scan_identifier_NULL */,
- TRUE /* scan_symbols */,
- FALSE /* scan_binary */,
- TRUE /* scan_octal */,
- TRUE /* scan_float */,
- TRUE /* scan_hex */,
- FALSE /* scan_hex_dollar */,
- TRUE /* scan_string_sq */,
- TRUE /* scan_string_dq */,
- TRUE /* numbers_2_int */,
- FALSE /* int_2_float */,
- FALSE /* identifier_2_string */,
- TRUE /* char_2_token */,
- FALSE /* symbol_2_token */,
- FALSE /* scope_0_fallback */,
-};
-
-
-enum _searchtermtype_t {
- SEARCH_AND,
- SEARCH_OR,
- SEARCH_LT,
- SEARCH_GT,
- SEARCH_EQ,
- SEARCH_CONTAINS,
- SEARCH_DATESENT,
- SEARCH_STRING,
- SEARCH_INT,
- SEARCH_FUNC,
-};
-
-struct _searchterm {
- enum _searchtermtype_t type;
- union {
- char *string;
- int number;
- struct {
- struct _searchterm_symbol *sym;
- struct _searchterm **terms;
- int termcount;
- } func;
- } value;
-};
struct _searchcontext {
int whatever;
@@ -178,69 +88,10 @@ struct _searchcontext {
CamelMessageInfo *message_current; /* when performing a (match operation */
};
-enum _searchresulttype_t {
- RESULT_ARRAY_PTR=0,
- RESULT_INT,
- RESULT_STRING,
- RESULT_BOOL,
- RESULT_UNDEFINED
-};
-
-struct _searchresult {
- enum _searchresulttype_t type;
- union {
- GPtrArray *ptrarray;
- int number;
- char *string;
- int bool;
- } value;
-};
-
-/* function callbacks */
-static struct _searchresult *search_contains(struct _searchcontext *ctx, struct _searchterm *t);
-static struct _searchresult *search_matches(struct _searchcontext *ctx, struct _searchterm *t);
-static struct _searchresult *search_date_sent(struct _searchcontext *ctx, struct _searchterm *t);
-static struct _searchresult *header_contains(struct _searchcontext *ctx, struct _searchterm *t);
-
-struct _searchterm_symbol {
- char *name;
- int type;
- int argtype;
- struct _searchresult * (*func)(struct _searchcontext *ctx, struct _searchterm *t);
-} symbols[] = {
- { "and", SEARCH_AND, 0, NULL },
- { "or", SEARCH_OR, 0, NULL },
- { "lt", SEARCH_LT, 1, NULL },
- { "gt", SEARCH_GT, 1, NULL },
- { "eq", SEARCH_EQ, 1, NULL },
- { "contains", SEARCH_FUNC, 1, search_contains },
- { "match-all", SEARCH_FUNC, 1, search_matches },
- { "date-sent", SEARCH_FUNC, 1, search_date_sent },
- { "header-contains", SEARCH_FUNC, 1, header_contains },
-};
-
-static struct _searchterm * parse_list(GScanner *gs, int gotbrace);
-static struct _searchterm * parse_value(GScanner *gs);
-
-static struct _searchresult *term_eval(struct _searchcontext *ctx, struct _searchterm *t);
-static void parse_dump_term(struct _searchterm *t, int depth);
-
-/* can you tell, i dont like glib? */
struct _glib_sux_donkeys {
int count;
GPtrArray *uids;
};
-
-
-/* ok, store any values that are in all sets */
-static void
-g_lib_sux_htand(char *key, int value, struct _glib_sux_donkeys *fuckup)
-{
- if (value == fuckup->count) {
- g_ptr_array_add(fuckup->uids, key);
- }
-}
-
/* or, store all unique values */
static void
g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup)
@@ -248,611 +99,225 @@ g_lib_sux_htor(char *key, int value, struct _glib_sux_donkeys *fuckup)
g_ptr_array_add(fuckup->uids, key);
}
-static struct _searchresult *
-result_new(int type)
-{
- struct _searchresult *r = g_malloc0(sizeof(*r));
- r->type = type;
- return r;
-}
-
-static void
-result_free(struct _searchresult *t)
-{
- switch(t->type) {
- case RESULT_ARRAY_PTR:
- g_ptr_array_free(t->value.ptrarray, TRUE);
- break;
- case RESULT_BOOL:
- case RESULT_INT:
- break;
- case RESULT_STRING:
- g_free(t->value.string);
- break;
- case RESULT_UNDEFINED:
- break;
- }
- g_free(t);
-}
-
-static struct _searchresult *search_contains(struct _searchcontext *ctx, struct _searchterm *t)
+static FilterSEXPResult *
+func_body_contains(struct _FilterSEXP *f, int argc, struct _FilterSEXPResult **argv, void *data)
{
- struct _searchresult *r, *r1;
-
- r = result_new(RESULT_UNDEFINED);
-
- if (t->value.func.termcount>0) {
- if (t->value.func.termcount!=1) {
- printf("warning, only looking for first string in contains clause\n");
- }
- r1 = term_eval(ctx, t->value.func.terms[0]);
- if (r1->type == RESULT_STRING) {
- if (ctx->message_current) {
- int truth = FALSE;
-#ifdef HAVE_IBEX
- int i;
- GPtrArray *array;
+ FilterSEXPResult *r;
+ int i, j;
+ struct _searchcontext *ctx = data;
- if (ctx->index) {
- array = ibex_find(ctx->index, r1->value.string);
+ if (ctx->message_current) {
+ int truth = FALSE;
- for (i=0;i<array->len;i++) {
- if (!strcmp(g_ptr_array_index(array, i), ctx->message_current->uid)) {
- truth = TRUE;
- break;
- }
- }
- g_ptr_array_free(array, TRUE);
- }
-#endif
- r->type = RESULT_BOOL;
- r->value.bool = truth;
- } else {
- r->type = RESULT_ARRAY_PTR;
-#ifdef HAVE_IBEX
- if (ctx->index) {
- /* blah, this should probably copy the index strings? */
- r->value.ptrarray = ibex_find(ctx->index, r1->value.string);
+ r = filter_sexp_result_new(FSEXP_RES_BOOL);
+ if (ctx->index) {
+ for (i=0;i<argc && !truth;i++) {
+ if (argv[i]->type == FSEXP_RES_STRING) {
+ truth = ibex_find_name(ctx->index, ctx->message_current->uid, argv[i]->value.string);
} else {
- r->value.ptrarray = g_ptr_array_new();
+ g_warning("Invalid type passed to body-contains match function");
}
-#endif
}
} else {
- printf("you can't search for a contents of a non-string, fool\n");
+ g_warning("Cannot perform indexed query with no index");
}
- result_free(r1);
- }
- return r;
-}
-
-/* run a sub-tree of commands which match on header fields etc */
-static struct _searchresult *search_matches(struct _searchcontext *ctx, struct _searchterm *t)
-{
- int i;
- struct _searchresult *r, *r1;
-
- if (t->value.func.termcount == 1) {
- r = result_new(RESULT_ARRAY_PTR);
- r->value.ptrarray = g_ptr_array_new();
+ r->value.bool = truth;
+ } else {
+ r = filter_sexp_result_new(FSEXP_RES_ARRAY_PTR);
- for (i=0;i<ctx->message_info->len;i++) {
- ctx->message_current = &g_array_index(ctx->message_info, CamelMessageInfo, i);
- r1 = term_eval(ctx, t->value.func.terms[0]);
- if (r1->type == RESULT_BOOL) {
- if (r1->value.bool) {
- r(printf("adding message %s\n", ctx->message_current->uid));
- g_ptr_array_add(r->value.ptrarray, ctx->message_current->uid);
- }
+ if (ctx->index) {
+ if (argc==1) {
+ /* common case */
+ r->value.ptrarray = ibex_find(ctx->index, argv[0]->value.string);
} else {
- printf("invalid syntax, matches require a single bool result\n");
+ 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 == FSEXP_RES_STRING) {
+ pa = ibex_find(ctx->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);
+ }
+ }
+ lambdafoo.uids = g_ptr_array_new();
+ g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
+ r->value.ptrarray = lambdafoo.uids;
}
- result_free(r1);
+ } else {
+ r->value.ptrarray = g_ptr_array_new();
}
- ctx->message_current = NULL;
- } else {
- r = result_new(RESULT_UNDEFINED);
- printf("invalid syntax, matches only allows a single bool arg\n");
}
- return r;
-}
-
-/* these variable-getting things could be put into 1 function */
-static struct _searchresult *search_date_sent(struct _searchcontext *ctx, struct _searchterm *t)
-{
- struct _searchresult *r;
- if (ctx->message_current) {
- r = result_new(RESULT_INT);
- r->value.number = time(0);
- /* r->value.number = ctx->current_message->date_sent;*/
- } else {
- r = result_new(RESULT_UNDEFINED);
- }
return r;
}
-/* header contains - can only be used inside a match-all construct */
-/* all headers should be inside a lookup table, so this can search
- all header types */
-static struct _searchresult *header_contains(struct _searchcontext *ctx, struct _searchterm *t)
+static FilterSEXPResult *
+func_date_sent(struct _FilterSEXP *f, int argc, struct _FilterSEXPResult **argv, void *data)
{
- struct _searchresult *r;
+ FilterSEXPResult *r;
+ struct _searchcontext *ctx = data;
- r(printf("executing header-contains\n"));
-
- /* are we inside a match-all? */
- if (ctx->message_current
- && t->value.func.termcount == 2) {
- char *header, *substring;
- int truth = FALSE;
- struct _searchresult *r1, *r2;
-
- r1 = term_eval(ctx, t->value.func.terms[0]);
- r2 = term_eval(ctx, t->value.func.terms[1]);
-
- if (r1->type == RESULT_STRING
- && r2->type == RESULT_STRING) {
-
- header = r1->value.string;
- substring = r2->value.string;
- if (!strcasecmp(header, "subject")) {
- r(printf("comparing subject: %s\n", ctx->message_current->subject));
- if (ctx->message_current->subject)
- truth = (strstr(ctx->message_current->subject, substring)) != NULL;
- else
- printf("Warning: no subject line in message?\n");
- }
- r(printf("header-contains %s %s = %s\n", header, substring, truth?"TRUE":"FALSE"));
- }
+ r = filter_sexp_result_new(FSEXP_RES_INT);
- result_free(r1);
- result_free(r2);
-
- r = result_new(RESULT_BOOL);
- r->value.number = truth;
+ if (ctx->message_current) {
+ g_warning("FIXME: implement date parsing ...");
+ /* r->value.number = get_date(ctx->message_current); */
} else {
- r = result_new(RESULT_UNDEFINED);
+ r->value.number = time(0);
}
return r;
}
-static struct _searchresult *
-term_eval(struct _searchcontext *ctx, struct _searchterm *t)
+static FilterSEXPResult *
+func_match_all(struct _FilterSEXP *f, int argc, struct _FilterSEXPTerm **argv, void *data)
{
- struct _searchresult *r, *r1, *r2;
int i;
+ FilterSEXPResult *r, *r1;
+ struct _searchcontext *ctx = data;
- r(printf("eval term :\n"));
- r(parse_dump_term(t, 0));
-
- r = g_malloc0(sizeof(*r));
- r->type = RESULT_UNDEFINED;
-
- switch (t->type) {
- case SEARCH_AND: {
- GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
- struct _glib_sux_donkeys lambdafoo;
- int type=-1;
- int bool = TRUE;
-
- r(printf("( and\n"));
-
- for (i=0;bool && i<t->value.func.termcount;i++) {
- r1 = term_eval(ctx, t->value.func.terms[i]);
- if (type == -1)
- type = r1->type;
- if (type != r1->type) {
- printf("invalid types in and operation, all types must be the same\n");
- } else if ( r1->type == RESULT_ARRAY_PTR ) {
- char **a1;
- int l1, j;
-
- a1 = (char **)r1->value.ptrarray->pdata;
- l1 = r1->value.ptrarray->len;
- for (j=0;i<l1;j++) {
- int n;
- n = (int)g_hash_table_lookup(ht, a1[i]);
- g_hash_table_insert(ht, a1[i], (void *)n+1);
- }
- } else if ( r1->type == RESULT_BOOL ) {
- bool &= r1->value.bool;
- }
- result_free(r1);
- }
-
- if (type == RESULT_ARRAY_PTR) {
- lambdafoo.count = t->value.func.termcount;
- lambdafoo.uids = g_ptr_array_new();
- g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htand, &lambdafoo);
- r->type = RESULT_ARRAY_PTR;
- r->value.ptrarray = lambdafoo.uids;
- } else if (type == RESULT_BOOL) {
- r->type = RESULT_BOOL;
- r->value.bool = bool;
- }
-
- g_hash_table_destroy(ht);
-
- break; }
- case SEARCH_OR: {
- GHashTable *ht = g_hash_table_new(g_str_hash, g_str_equal);
- struct _glib_sux_donkeys lambdafoo;
- int type = -1;
- int bool = FALSE;
-
- r(printf("(or \n"));
-
- for (i=0;!bool && i<t->value.func.termcount;i++) {
- r1 = term_eval(ctx, t->value.func.terms[i]);
- if (type == -1)
- type = r1->type;
- if (r1->type != type) {
- printf("wrong types in or operation\n");
- } else if (r1->type == RESULT_ARRAY_PTR) {
- char **a1;
- int l1, j;
-
- a1 = (char **)r1->value.ptrarray->pdata;
- l1 = r1->value.ptrarray->len;
- for (j=0;i<l1;j++) {
- g_hash_table_insert(ht, a1[j], (void *)1);
- }
- } else if (r1->type == RESULT_BOOL) {
- bool |= r1->value.bool;
- }
- result_free(r1);
- }
+ if (argc>1) {
+ g_warning("match-all only takes a single argument, other arguments ignored");
+ }
+ r = filter_sexp_result_new(FSEXP_RES_ARRAY_PTR);
+ r->value.ptrarray = g_ptr_array_new();
- if (type == RESULT_ARRAY_PTR) {
- lambdafoo.count = t->value.func.termcount;
- lambdafoo.uids = g_ptr_array_new();
- g_hash_table_foreach(ht, (GHFunc)g_lib_sux_htor, &lambdafoo);
- r->type = RESULT_ARRAY_PTR;
- r->value.ptrarray = lambdafoo.uids;
- } else if (type == RESULT_BOOL) {
- r->type = RESULT_BOOL;
- r->value.bool = bool;
- }
- g_hash_table_destroy(ht);
-
- break; }
- case SEARCH_LT:
- r(printf("(lt \n"));
- if (t->value.func.termcount == 2) {
- r1 = term_eval(ctx, t->value.func.terms[0]);
- r2 = term_eval(ctx, t->value.func.terms[1]);
- if (r1->type != r2->type) {
- printf("error, invalid types in compare\n");
- } else if (r1->type == RESULT_INT) {
- r->type = RESULT_BOOL;
- r->value.bool = r1->value.number < r2->value.number;
- } else if (r1->type == RESULT_STRING) {
- r->type = RESULT_BOOL;
- r->value.bool = strcmp(r1->value.string, r2->value.string) < 0;
- }
- }
- break;
- case SEARCH_GT:
- r(printf("(gt \n"));
- if (t->value.func.termcount == 2) {
- r1 = term_eval(ctx, t->value.func.terms[0]);
- r2 = term_eval(ctx, t->value.func.terms[1]);
- if (r1->type != r2->type) {
- printf("error, invalid types in compare\n");
- } else if (r1->type == RESULT_INT) {
- r->type = RESULT_BOOL;
- r->value.bool = r1->value.number > r2->value.number;
- } else if (r1->type == RESULT_STRING) {
- r->type = RESULT_BOOL;
- r->value.bool = strcmp(r1->value.string, r2->value.string) > 0;
+ for (i=0;i<ctx->message_info->len;i++) {
+ if (argc>0) {
+ ctx->message_current = &g_array_index(ctx->message_info, CamelMessageInfo, i);
+ r1 = filter_sexp_term_eval(f, argv[0]);
+ if (r1->type == FSEXP_RES_BOOL) {
+ if (r1->value.bool)
+ g_ptr_array_add(r->value.ptrarray, ctx->message_current->uid);
+ } else {
+ g_warning("invalid syntax, matches require a single bool result");
}
+ filter_sexp_result_free(r1);
+ } else {
+ g_ptr_array_add(r->value.ptrarray, ctx->message_current->uid);
}
- break;
- case SEARCH_STRING:
- r(printf(" (string \"%s\")\n", t->value.string));
- r->type = RESULT_STRING;
- /* erk, this shoul;dn't need to strdup this ... */
- r->value.string = g_strdup(t->value.string);
- break;
- case SEARCH_INT:
- r(printf(" (int %d)\n", t->value.number));
- r->type = RESULT_INT;
- r->value.number = t->value.number;
- break;
- case SEARCH_FUNC:
- g_free(r); /* <---- FIXME: ICK !! */
- r(printf("function '%s'\n", t->value.func.sym->name));
- return t->value.func.sym->func(ctx, t);
- default:
- printf("Warning: Unknown type encountered in parse tree: %d\n", t->type);
- r->type = RESULT_UNDEFINED;
}
+ ctx->message_current = NULL;
return r;
}
-
-static void
-parse_dump_term(struct _searchterm *t, int depth)
+static FilterSEXPResult *
+func_header_contains(struct _FilterSEXP *f, int argc, struct _FilterSEXPResult **argv, void *data)
{
- int dumpvals = FALSE;
- int i;
-
- if (t==NULL) {
- printf("null term??\n");
- return;
- }
+ FilterSEXPResult *r;
+ struct _searchcontext *ctx = data;
+ int truth = FALSE;
- for (i=0;i<depth;i++)
- printf(" ");
-
- switch (t->type) {
- case SEARCH_AND:
- printf("(and \n");
- dumpvals = 1;
- break;
- case SEARCH_OR:
- printf("(or \n");
- dumpvals = 1;
- break;
- case SEARCH_LT:
- printf("(lt \n");
- dumpvals = 1;
- break;
- case SEARCH_GT:
- printf("(gt \n");
- dumpvals = 1;
- break;
- case SEARCH_STRING:
- printf(" \"%s\"", t->value.string);
- break;
- case SEARCH_INT:
- printf(" %d", t->value.number);
- break;
- case SEARCH_FUNC:
- printf(" (function %s", t->value.func.sym->name);
- dumpvals = 1;
- break;
- default:
- printf("unknown type: %d\n", t->type);
- }
+ r(printf("executing header-contains\n"));
- if (dumpvals) {
- /*printf(" [%d] ", t->value.func.termcount);*/
- for (i=0;i<t->value.func.termcount;i++) {
- parse_dump_term(t->value.func.terms[i], depth+1);
+ /* are we inside a match-all? */
+ if (ctx->message_current && argc>1
+ && argv[0]->type == FSEXP_RES_STRING) {
+ char *headername, *header;
+ int i;
+
+ /* only a subset of headers are supported .. */
+ headername = argv[0]->value.string;
+ if (!strcasecmp(headername, "subject")) {
+ header = ctx->message_current->subject;
+ } else if (!strcasecmp(headername, "date")) {
+ header = ctx->message_current->date;
+ } else if (!strcasecmp(headername, "from")) {
+ header = ctx->message_current->sender;
+ } else {
+ g_warning("Performing query on unknown header: %s", headername);
+ header = NULL;
}
- for (i=0;i<depth;i++)
- printf(" ");
- printf(")\n");
- }
- printf("\n");
-}
-
-/*
- PARSER
-*/
-
-static struct _searchterm *
-parse_new_term(int type)
-{
- struct _searchterm *s = g_malloc0(sizeof(*s));
- s->type = type;
- return s;
-}
-static void
-parse_term_free(struct _searchterm *t)
-{
- int i;
-
- if (t==NULL) {
- return;
- }
-
- switch (t->type) {
- case SEARCH_AND:
- case SEARCH_OR:
- case SEARCH_LT:
- case SEARCH_GT:
- case SEARCH_FUNC:
- for (i=0;i<t->value.func.termcount;i++) {
- parse_term_free(t->value.func.terms[i]);
+ if (header) {
+ for (i=1;i<argc && !truth;i++) {
+ if (argv[i]->type == FSEXP_RES_STRING
+ && strstr(header, argv[i]->value.string)) {
+ printf("%s got a match with %s of %s\n", ctx->message_current->uid, header, argv[i]->value.string);
+ truth = TRUE;
+ break;
+ }
+ }
}
- g_free(t->value.func.terms);
- break;
- case SEARCH_STRING:
- g_free(t->value.string);
- break;
- case SEARCH_INT:
- break;
- default:
- printf("parse_term_free: unknown type: %d\n", t->type);
}
- g_free(t);
-}
-
-static struct _searchterm **
-parse_lists(GScanner *gs, int *len)
-{
- int token;
- struct _searchterm **terms;
- int i=0;
+ r = filter_sexp_result_new(FSEXP_RES_BOOL);
+ r->value.bool = truth;
- p(printf("parsing lists\n"));
-
- terms = g_malloc0(20*sizeof(*terms));
-
- while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF
- && token != ')') {
- terms[i]=parse_list(gs, FALSE);
- i++;
- }
-
- if (len)
- *len = i;
-
- p(printf("found %d subterms\n", i));
-
- p(printf("done parsing lists, token= %d %c\n", token, token));
- return terms;
+ return r;
}
-static struct _searchterm **
-parse_values(GScanner *gs, int *len)
-{
- int token;
- struct _searchterm **terms;
- int i=0;
-
- p(printf("parsing values\n"));
-
- terms = g_malloc0(20*sizeof(*terms));
-
- while ( (token = g_scanner_peek_next_token(gs)) != G_TOKEN_EOF
- && token != ')') {
- terms[i]=parse_value(gs);
- i++;
- }
- p(printf("found %d subterms\n", i));
- *len = i;
-
- p(printf("dont parsing values\n"));
- return terms;
-}
+/* 'builtin' functions */
+static struct {
+ char *name;
+ FilterSEXPFunc *func;
+ int type; /* set to 1 if a function can perform shortcut evaluation, or
+ doesn't execute everything, 0 otherwise */
+} symbols[] = {
+ { "body-contains", func_body_contains, 0 },
+ { "date-sent", func_date_sent, 0 },
+ { "match-all", (FilterSEXPFunc *)func_match_all, 1 },
+ { "header-contains", func_header_contains, 0 },
+};
-static struct _searchterm *
-parse_value(GScanner *gs)
+GList *
+camel_mbox_folder_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex)
{
- int token;
- struct _searchterm *t = NULL;
-
- p(printf("parsing value\n"));
-
- token = g_scanner_get_next_token(gs);
- switch(token) {
- case G_TOKEN_LEFT_PAREN:
- p(printf("got brace, its a list!\n"));
- return parse_list(gs, TRUE);
- case G_TOKEN_STRING:
- p(printf("got string\n"));
- t = parse_new_term(SEARCH_STRING);
- t->value.string = g_strdup(g_scanner_cur_value(gs).v_string);
- break;
- case G_TOKEN_INT:
- t = parse_new_term(SEARCH_INT);
- t->value.number = g_scanner_cur_value(gs).v_int;
- p(printf("got int\n"));
- break;
- default:
- printf("Innvalid token trying to parse a list of values\n");
+ int i;
+ struct _searchcontext ctx;
+ GList *matches = NULL;
+ FilterSEXP *f;
+ FilterSEXPResult *r;
+
+ /* setup our expression evaluator */
+ f = filter_sexp_new();
+
+ /* setup out context */
+ ctx.folder = folder;
+ ctx.summary = camel_folder_get_summary(folder, ex);
+ ctx.message_info = camel_folder_summary_get_message_info_list(ctx.summary);
+ ctx.message_current = NULL;
+ ctx.index = ibex_open(CAMEL_MBOX_FOLDER(folder)->index_file_path, FALSE);
+ if (!ctx.index) {
+ perror("Cannot open index file");
}
- p(printf("done parsing value\n"));
- return t;
-}
-/* FIXME: this needs some robustification */
-static struct _searchterm *
-parse_list(GScanner *gs, int gotbrace)
-{
- int token;
- struct _searchterm *t = NULL;
-
- p(printf("parsing list\n"));
- if (gotbrace)
- token = '(';
- else
- token = g_scanner_get_next_token(gs);
- if (token =='(') {
- token = g_scanner_get_next_token(gs);
- if (token == G_TOKEN_SYMBOL) {
- struct _searchterm_symbol *s;
-
- s = g_scanner_cur_value(gs).v_symbol;
- p(printf("got funciton: %s\n", s->name));
- t = parse_new_term(s->type);
- t->value.func.sym = s;
- p(printf("created new list %p\n", t));
- switch(s->argtype) {
- case 0: /* it MUST be a list of lists */
- t->value.func.terms = parse_lists(gs, &t->value.func.termcount);
- break;
- case 1:
- t->value.func.terms = parse_values(gs, &t->value.func.termcount);
- break;
- default:
- printf("Error, internal error parsing symbols\n");
- }
+ for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++) {
+ if (symbols[i].type == 1) {
+ filter_sexp_add_ifunction(f, 0, symbols[i].name, (FilterSEXPIFunc *)symbols[i].func, &ctx);
} else {
- printf("unknown sequence encountered, type = %d\n", token);
+ filter_sexp_add_function(f, 0, symbols[i].name, symbols[i].func, &ctx);
}
- token = g_scanner_get_next_token(gs);
- if (token != ')') {
- printf("Error, expected ')' not found\n");
- }
- } else {
- printf("Error, list term without opening (\n");
}
- p(printf("returning list %p\n", t));
- return t;
-}
-
-GList *
-camel_mbox_folder_search_by_expression(CamelFolder *folder, char *expression, CamelException *ex)
-{
- GScanner *gs;
- int i;
- struct _searchterm *t;
- struct _searchcontext *ctx;
- struct _searchresult *r;
- GList *matches = NULL;
-
- gs = g_scanner_new(&scanner_config);
- for(i=0;i<sizeof(symbols)/sizeof(symbols[0]);i++)
- g_scanner_scope_add_symbol(gs, 0, symbols[i].name, &symbols[i]);
-
- g_scanner_input_text(gs, expression, strlen(expression));
- t = parse_list(gs, 0);
-
- if (t) {
- ctx = g_malloc0(sizeof(*ctx));
- ctx->folder = folder;
- ctx->summary = camel_folder_get_summary(folder, ex);
- ctx->message_info = camel_folder_summary_get_message_info_list(ctx->summary);
-#ifdef HAVE_IBEX
- ctx->index = ibex_open(CAMEL_MBOX_FOLDER(folder)->index_file_path, FALSE);
- if (!ctx->index) {
- perror("Cannot open index file, body searches will be ignored\n");
- }
-#endif
- r = term_eval(ctx, t);
-
- /* now create a folder summary to return?? */
- if (r
- && r->type == RESULT_ARRAY_PTR) {
- d(printf("got result ...\n"));
- for (i=0;i<r->value.ptrarray->len;i++) {
- d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
- matches = g_list_prepend(matches, g_strdup(g_ptr_array_index(r->value.ptrarray, i)));
- }
- result_free(r);
+ filter_sexp_input_text(f, expression, strlen(expression));
+ filter_sexp_parse(f);
+ r = filter_sexp_eval(f);
+
+ /* now create a folder summary to return?? */
+ if (r
+ && r->type == FSEXP_RES_ARRAY_PTR) {
+ d(printf("got result ...\n"));
+ for (i=0;i<r->value.ptrarray->len;i++) {
+ d(printf("adding match: %s\n", (char *)g_ptr_array_index(r->value.ptrarray, i)));
+ matches = g_list_prepend(matches, g_strdup(g_ptr_array_index(r->value.ptrarray, i)));
}
-
- if (ctx->index)
- ibex_close(ctx->index);
-
- gtk_object_unref((GtkObject *)ctx->summary);
- g_free(ctx);
- parse_term_free(t);
+ filter_sexp_result_free(r);
} else {
- printf("Warning, Could not parse expression!\n %s\n", expression);
+ printf("no result!\n");
}
- g_scanner_destroy(gs);
+ if (ctx.index)
+ ibex_close(ctx.index);
+
+ gtk_object_unref((GtkObject *)ctx.summary);
+ gtk_object_unref((GtkObject *)f);
return matches;
}