diff options
author | NotZed <NotZed@HelixCode.com> | 2000-02-19 12:12:40 +0800 |
---|---|---|
committer | Michael Zucci <zucchi@src.gnome.org> | 2000-02-19 12:12:40 +0800 |
commit | 1c70e0090563eb9acfbcd59dcecbc833154d3747 (patch) | |
tree | 8cd04cf8629ba676bfd1979021250d31acb401f3 | |
parent | f1e7572b78fe6bda6b1e76457a7637de07a9842c (diff) | |
download | gsoc2013-evolution-1c70e0090563eb9acfbcd59dcecbc833154d3747.tar gsoc2013-evolution-1c70e0090563eb9acfbcd59dcecbc833154d3747.tar.gz gsoc2013-evolution-1c70e0090563eb9acfbcd59dcecbc833154d3747.tar.bz2 gsoc2013-evolution-1c70e0090563eb9acfbcd59dcecbc833154d3747.tar.lz gsoc2013-evolution-1c70e0090563eb9acfbcd59dcecbc833154d3747.tar.xz gsoc2013-evolution-1c70e0090563eb9acfbcd59dcecbc833154d3747.tar.zst gsoc2013-evolution-1c70e0090563eb9acfbcd59dcecbc833154d3747.zip |
Added exception to call, and fixed caller.
2000-02-18 NotZed <NotZed@HelixCode.com>
* providers/mbox/camel-mbox-search.h
(camel_mbox_folder_search_by_expression): Added exception to call,
and fixed caller.
* providers/mbox/camel-mbox-search.c
(camel_mbox_folder_search_by_expression): Major changes, to use
the sexp evaluator from filter/filter-sexp.c to implement the
searching.
(func_body_contains): Changed to support multiple strings in 1
command (results or'd together)
* url-util.c (g_url_new): Fixed a typo (colon == 0 isn't right),
and made it so full url's are absolute pathed (Dan, this is how it
has to work!). Also, always include a path part, even if it is an
empty string.
2000-02-16 NotZed <NotZed@HelixCode.com>
* providers/mbox/Makefile.am (libcamelmbox_la_LIBADD): Added
libfilter to link line (temporarily?). Required for
filter-sexp.
svn path=/trunk/; revision=1855
-rw-r--r-- | camel/ChangeLog | 50 | ||||
-rw-r--r-- | camel/providers/mbox/Makefile.am | 10 | ||||
-rw-r--r-- | camel/providers/mbox/camel-mbox-folder.c | 2 | ||||
-rw-r--r-- | camel/providers/mbox/camel-mbox-search.c | 873 | ||||
-rw-r--r-- | camel/providers/mbox/camel-mbox-search.h | 2 | ||||
-rw-r--r-- | camel/url-util.c | 13 |
6 files changed, 238 insertions, 712 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog new file mode 100644 index 0000000000..d5f31c002c --- /dev/null +++ b/camel/ChangeLog @@ -0,0 +1,50 @@ +2000-02-18 NotZed <NotZed@HelixCode.com> + + * providers/mbox/camel-mbox-search.h + (camel_mbox_folder_search_by_expression): Added exception to call, + and fixed caller. + + * providers/mbox/camel-mbox-search.c + (camel_mbox_folder_search_by_expression): Major changes, to use + the sexp evaluator from filter/filter-sexp.c to implement the + searching. + (func_body_contains): Changed to support multiple strings in 1 + command (results or'd together) + + * url-util.c (g_url_new): Fixed a typo (colon == 0 isn't right), + and made it so full url's are absolute pathed (Dan, this is how it + has to work!). Also, always include a path part, even if it is an + empty string. + +2000-02-16 NotZed <NotZed@HelixCode.com> + + * providers/mbox/Makefile.am (libcamelmbox_la_LIBADD): Added + libfilter to link line (temporarily?). Required for + filter-sexp. + +2000-02-13 NotZed <notzed@zedzone.helixcode.com> + + * providers/mbox/camel-mbox-search.c: New file, implements the + search api for mbox folders. + + * providers/mbox/Makefile.am: Link with ibex. + + * camel-folder.c (camel_folder_has_search_capability): Api + additions. + (camel_folder_search_by_expression): Ditto. + +2000-02-12 NotZed <notzed@zedzone.helixcode.com> + + * providers/mbox/camel-mbox-folder.c (_set_name): Setup index + filename as well. + (_init_with_store): Init index filename. Hmm, none of these + names ever seem to get free'd (FIXME?) + + * providers/mbox/camel-mbox-folder.h: Add index file name. + +2000-02-12 NotZed <notzed@helixcode.com> + + * camel-folder.h: Add folder search functions. + + ** Created ChangeLog just for camel ** + - refer to ../ChangeLog for changes prior to this date. diff --git a/camel/providers/mbox/Makefile.am b/camel/providers/mbox/Makefile.am index 4edbb945af..11e004a5ea 100644 --- a/camel/providers/mbox/Makefile.am +++ b/camel/providers/mbox/Makefile.am @@ -12,7 +12,8 @@ provider_LTLIBRARIES = libcamelmbox.la INCLUDES = -I.. -I$(srcdir)/.. -I$(includedir) \ -I$(top_srcdir)/intl \ $(GTK_INCLUDEDIR) -I$(top_srcdir)/camel \ - -I$(top_srcdir)/libibex + -I$(top_srcdir)/libibex \ + -I$(top_srcdir)/filter libcamelmbox_la_SOURCES = \ camel-mbox-folder.c \ @@ -34,7 +35,12 @@ libcamelmboxinclude_HEADERS = \ libcamelmbox_la_LDFLAGS = -version-info 0:0:0 -rpath $(libdir) -libcamelmbox_la_LIBADD = -L$(top_builddir)/libibex -libex +#libcamelmbox_la_LIBADD = -L$(top_srcdir)/libibex -libex +libcamelmbox_la_LIBADD = $(top_srcdir)/filter/libfilter.la +##libcamelmbox_la_LIBADD = -L$(top_builddir)/libibex -libex +##libcamelmbox_la_LIBADD = $(top_builddir)/libibex/libibex.la $(UNICODE_LIBS) +##libcamelmbox_la_LIBADD = $(UNICODE_LIBS) +#libcamelmbox_la_LIBADD = -L$(top_builddir)/libibex -libex #libcamelmbox_la_LIBADD = $(top_builddir)/libibex/libibex.la $(UNICODE_LIBS) #libcamelmbox_la_LIBADD = $(UNICODE_LIBS) diff --git a/camel/providers/mbox/camel-mbox-folder.c b/camel/providers/mbox/camel-mbox-folder.c index 2743423a66..7eeaff691b 100644 --- a/camel/providers/mbox/camel-mbox-folder.c +++ b/camel/providers/mbox/camel-mbox-folder.c @@ -1129,5 +1129,5 @@ _get_message_by_uid (CamelFolder *folder, const gchar *uid, CamelException *ex) static CamelFolderSummary * search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex) { - return camel_mbox_folder_search_by_expression(folder, expression); + return camel_mbox_folder_search_by_expression(folder, expression, ex); } 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; } diff --git a/camel/providers/mbox/camel-mbox-search.h b/camel/providers/mbox/camel-mbox-search.h index 16efd4a023..d232624386 100644 --- a/camel/providers/mbox/camel-mbox-search.h +++ b/camel/providers/mbox/camel-mbox-search.h @@ -4,7 +4,7 @@ #include "camel-mbox-folder.h" -GList *camel_mbox_folder_search_by_expression(CamelFolder *folder, const char *expression); +GList *camel_mbox_folder_search_by_expression(CamelFolder *folder, const char *expression, CamelException *ex); #endif /* ! _CAMEL_MBOX_SEARCH_H */ diff --git a/camel/url-util.c b/camel/url-util.c index da47e041d9..37a433888d 100644 --- a/camel/url-util.c +++ b/camel/url-util.c @@ -124,10 +124,15 @@ Gurl *g_url_new (const gchar* url_string) g_url->port = NULL; } - if (slash && *(slash + 1)) - g_url->path = g_strdup (slash); - else - g_url->path = NULL; + /* setup a fallback, if relative, then empty string, else + it will be from root */ + if (slash == NULL) { + slash = "/"; + } + if (slash && *slash && g_url->protocol == NULL) + slash++; + + g_url->path = g_strdup (slash); return g_url; } |