From 65d4250703d68534210c57f4ed413f95b24390d3 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Thu, 31 Aug 2000 21:08:14 +0000 Subject: Reimplemented. It should now work correctly for most possible VFolder 2000-08-31 Jeffrey Stedfast * providers/imap/camel-imap-utils.c (imap_translate_sexp): Reimplemented. It should now work correctly for most possible VFolder rules. svn path=/trunk/; revision=5151 --- camel/ChangeLog | 6 + camel/providers/imap/camel-imap-utils.c | 502 +++++++++++++++++++++----------- 2 files changed, 333 insertions(+), 175 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index 7d286ccf31..4c3a60d500 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,9 @@ +2000-08-31 Jeffrey Stedfast + + * providers/imap/camel-imap-utils.c (imap_translate_sexp): + Reimplemented. It should now work correctly for most possible + VFolder rules. + 2000-08-31 Jeffrey Stedfast * providers/imap/camel-imap-store.c (camel_imap_command_extended): diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c index 7bb5044564..d25a2f5159 100644 --- a/camel/providers/imap/camel-imap-utils.c +++ b/camel/providers/imap/camel-imap-utils.c @@ -22,6 +22,7 @@ #include #include +#include #include #include "camel-imap-utils.h" @@ -30,23 +31,8 @@ #define d(x) x -static char *esexp_keys[] = { "and", "or", "body-contains", "header-contains", "match-all", "user-flag", NULL }; -static char *imap_keys[] = { NULL, "OR", "BODY", "HEADER", NULL, NULL }; - -struct sexp_node { - struct sexp_node *l_node, *r_node; - char *function; - char *data; -}; - static char *get_quoted_token (char *string, int *len); static char *get_token (char *string, int *len); -struct sexp_node *get_sexp_node (const char *exp); -static void print_node (struct sexp_node *node, int depth); -static const char *get_func (struct sexp_node *node); -static char *get_data (struct sexp_node *node); -static char *str_sexp_node (struct sexp_node *node); -static void free_sexp_node (struct sexp_node *node); char * @@ -162,230 +148,396 @@ get_token (char *string, int *len) return g_strndup (p, *len); } -struct sexp_node * -get_sexp_node (const char *exp) +static ESExpResult * +func_and (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - struct sexp_node *node = NULL; - char *left_exp, *right_exp, *this_exp; - char *p, *ep; - int len, pbal; - - if (exp && *exp) { - node = g_malloc0 (sizeof (struct sexp_node)); - node->l_node = NULL; - node->r_node = NULL; - node->function = NULL; - node->data = NULL; + GList **list = data; + ESExpResult *r; + + fprintf (stderr, "in AND func (argc = %d)\n", argc); + if (argc > 0) { + char **strings; + int i; + + strings = g_new (char*, argc+1); + strings[argc] = NULL; - p = (char *) exp + 1; - for (ep = p, pbal = 1; *ep && pbal; ep++) { - if (*ep == '(') - pbal++; - if (*ep == ')') - pbal--; + for (i = 0; i < argc; i++) { + GList *list_head = *list; + + fprintf (stderr, "\tAND func: %s\n", (*list) ? (char *) (*list)->data : "(null)"); + strings[argc - (i+1)] = (*list) ? (*list)->data : g_strdup (""); + *list = g_list_remove_link (*list, *list); + g_list_free_1 (list_head); } - this_exp = g_strndup (p, (gint)(ep - p)); + *list = g_list_prepend (*list, g_strjoinv (" ", strings)); + fprintf (stderr, "%s\n", (char *) (*list)->data); - for (left_exp = ep; *left_exp && *left_exp != '('; left_exp++); - left_exp = g_strdup (left_exp); + for (i = 0 ; i < argc; i ++) + g_free (strings[i]); - for (right_exp = this_exp; *right_exp && *right_exp != '('; right_exp++); - pbal = 1; - for (ep = right_exp; *ep && pbal; ep++) { - if (*ep == '(') - pbal++; - if (*ep == ')') - pbal--; + g_free (strings); + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_or (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + fprintf (stderr, "in OR func (argc = %d)\n", argc); + if (argc == 2 && (*list)->data && (*list)->next && (*list)->next->data) { + char **strings; + int i; + + strings = g_new (char*, argc+2); + strings[0] = g_strdup ("OR"); + strings[argc+2 - 1] = NULL; + + for (i = 0; i < 2; i++) { + GList *list_head = *list; + + fprintf (stderr, "\tOR func: %s\n", (*list) ? (char *) (*list)->data : "(null)"); + strings[argc - i] = (*list) ? (*list)->data : g_strdup (""); + *list = g_list_remove_link (*list, *list); + g_list_free_1 (list_head); } - right_exp = g_strndup (right_exp, (gint)(ep - right_exp)); - /* fill in the node */ - node->function = get_token (this_exp, &len); - p = this_exp + len; - for (ep = p; *ep && *ep != '(' && *ep != ')'; ep++); - node->data = g_strndup (p, (gint)(ep - p)); + *list = g_list_prepend (*list, g_strjoinv (" ", strings)); + fprintf (stderr, "%s\n", (char *) (*list)->data); - g_strstrip (node->data); - - node->l_node = get_sexp_node (left_exp); - node->r_node = get_sexp_node (right_exp); + for (i = 0 ; i < argc + 2; i ++) + g_free (strings[i]); + + g_free (strings); + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} - g_free (this_exp); - g_free (left_exp); - g_free (right_exp); +static ESExpResult * +func_not (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; + + fprintf (stderr, "in NOT func\n"); + /* just replace the head of the list with the NOT of it. */ + if (argc > 0) { + char *term = (*list)->data; + + (*list)->data = g_strdup_printf ("NOT %s", term); + fprintf (stderr, "%s\n", (char *) (*list)->data); + g_free (term); } - return node; + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; } -static void -print_node (struct sexp_node *node, int depth) +static char *tz_months [] = { + "Jan", "Feb", "Mar", "Apr", "May", "Jun", + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" +}; + +static char * +format_date (time_t time, int offset) { - int i; + struct tm tm; - for (i = 0; i < depth; i++) - d(fprintf (stderr, " ")); + time += ((offset / 100) * (60*60)) + (offset % 100)*60; - d(fprintf (stderr, "%s\n", node->function)); + d(printf("converting date %s", ctime (&time))); - if (*node->data) { - for (i = 0; i < depth + 1; i++) - d(fprintf (stderr, " ")); + memcpy (&tm, gmtime (&time), sizeof (tm)); + + return g_strdup_printf ("%d-%s-%04d", + tm.tm_mday, tz_months[tm.tm_mon], + tm.tm_year + 1900); +} + +static ESExpResult * +func_lt (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + char *type = (*list)->data; + time_t date = (time_t) (argv[1])->value.number; + ESExpResult *r; + + fprintf (stderr, "in less-than func: (%d) (%s) (%d)\n", argc, type, (int) date); + if (argc > 0) { + char *string, *date_str; - d(fprintf (stderr, "%s\n", node->data)); + date_str = format_date (date, 0); + + if (!strcmp ("SENT", type)) { + string = g_strdup_printf ("SENTBEFORE \"%s\"", date_str); + } else { + string = g_strdup_printf ("BEFORE \"%s\"", date_str); + } + + (*list)->data = string; + g_free (type); } - if (node->r_node) - print_node (node->r_node, depth + 1); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - if (node->l_node) - print_node (node->l_node, depth); + return r; } -static const char * -get_func (struct sexp_node *node) +static ESExpResult * +func_gt (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - int i; + GList **list = data; + char *type = (*list)->data; + time_t date = (time_t) (argv[1])->value.number; + ESExpResult *r; + + fprintf (stderr, "in greater-than func: (%d) (%s) (%d)\n", argc, type, (int) date); + if (argc > 0) { + char *string, *date_str; + + date_str = format_date (date, 0); + + if (!strcmp ("SENT", type)) { + string = g_strdup_printf ("SENTSINCE \"%s\"", date_str); + } else { + string = g_strdup_printf ("SINCE \"%s\"", date_str); + } + + (*list)->data = string; + g_free (type); + } - for (i = 0; esexp_keys[i]; i++) - if (!strncmp (esexp_keys[i], node->function, strlen (node->function))) - break; + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - if (esexp_keys[i]) - return imap_keys[i]; - else - return node->function; + return r; } -static char * -get_data (struct sexp_node *node) +static ESExpResult * +func_eq (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + char *type = (*list)->data; + time_t date = (time_t) (argv[1])->value.number; + ESExpResult *r; + + fprintf (stderr, "in equal-to func: (%d) (%s) (%d)\n", argc, type, (int) date); + if (argc > 0) { + char *string, *date_str; + + date_str = format_date (date, 0); + + if (!strcmp ("SENT", type)) { + string = g_strdup_printf ("SENTON \"%s\"", date_str); + } else { + string = g_strdup_printf ("ON \"%s\"", date_str); + } + + (*list)->data = string; + g_free (type); + } + + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; +} + +static ESExpResult * +func_match_all (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - GPtrArray *args; - const char *func; - char *data, *token, *p; - int i, len; + /* match-all doesn't have a IMAP equiv */ + ESExpResult *r; - func = get_func (node); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - args = g_ptr_array_new (); + return r; +} + +static ESExpResult * +func_body_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + char *value = (*argv)->value.string; + ESExpResult *r; - p = node->data; - while (p && *p) { - token = get_token (p, &len); - g_ptr_array_add (args, token); - p += len; + if (argc > 0) { + char *string; + + string = g_strdup_printf ("BODY \"%s\"", value); + + *list = g_list_prepend (*list, string); } - if (func && !strcmp ("HEADER", func) && args->len > 0) - string_unquote (args->pdata[0]); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - if (args->len > 0) { - data = g_strjoinv (" ", (char **) args->pdata); - } else { - data = g_strdup (""); + return r; +} + +static ESExpResult * +func_header_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + char *header = (argv[0])->value.string; + char *match = (argv[1])->value.string; + ESExpResult *r; + + if (argc == 2) { + char *string; + string = g_strdup_printf ("HEADER %s \"%s\"", header, match); + + *list = g_list_prepend (*list, string); } - for (i = 0; i < args->len; i++) - g_free (args->pdata[i]); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - g_ptr_array_free (args, TRUE); + return r; +} + +static ESExpResult * +func_user_tag (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + /* FIXME: what do I do here? */ + ESExpResult *r; - return data; + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; + + return r; } -static char * -str_sexp_node (struct sexp_node *node) +static ESExpResult * +func_user_flag (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - char *node_str, *data, *str, *l_str, *r_str; - const char *func; + /* FIXME: what do I do here? */ + ESExpResult *r; - func = get_func (node); - data = get_data (node); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - if (func) { - if (*data) - str = g_strdup_printf ("%s %s", func, data); - else - str = g_strdup (func); - } else { - str = NULL; - } + return r; +} + +static ESExpResult * +func_get_sent_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; - g_free (data); + *list = g_list_prepend (*list, g_strdup ("SENT")); - r_str = NULL; - if (node->r_node) - r_str = str_sexp_node (node->r_node); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - l_str = NULL; - if (node->l_node) - l_str = str_sexp_node (node->l_node); + return r; +} + +static ESExpResult * +func_get_received_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + GList **list = data; + ESExpResult *r; - if (str) { - if (r_str) { - if (l_str) - node_str = g_strdup_printf ("%s %s %s", str, r_str, l_str); - else - node_str = g_strdup_printf ("%s %s", str, r_str); - } else { - if (l_str) - node_str = g_strdup_printf ("%s %s", str, l_str); - else - node_str = g_strdup_printf ("%s", str); - } - } else { - if (r_str) { - if (l_str) - node_str = g_strdup_printf ("%s %s", r_str, l_str); - else - node_str = g_strdup_printf ("%s", r_str); - } else { - if (l_str) - node_str = g_strdup_printf ("%s", l_str); - else - node_str = g_strdup (""); - } - } + *list = g_list_prepend (*list, g_strdup ("RECEIVED")); - g_free (str); - g_free (l_str); - g_free (r_str); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - return node_str; + return r; } -static void -free_sexp_node (struct sexp_node *node) +static ESExpResult * +func_get_current_date (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - if (node->r_node) - free_sexp_node (node->r_node); + /* FIXME: what do I do here? */ + ESExpResult *r; - if (node->l_node) - free_sexp_node (node->l_node); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - g_free (node->function); - g_free (node->data); - g_free (node); + return r; } +/* builtin functions */ +static struct { + char *name; + ESExpFunc *func; + int type; /* set to 1 if a function can perform shortcut evaluation, or + doesn't execute everything, 0 otherwise */ +} symbols[] = { + { "and", (ESExpFunc *) func_and, 0 }, + { "or", (ESExpFunc *) func_or, 0 }, + { "not", (ESExpFunc *) func_not, 0 }, + { "<", (ESExpFunc *) func_lt, 0 }, + { ">", (ESExpFunc *) func_gt, 0 }, + { "=", (ESExpFunc *) func_eq, 0 }, + { "match-all", (ESExpFunc *) func_match_all, 0 }, + { "body-contains", (ESExpFunc *) func_body_contains, 0 }, + { "header-contains", (ESExpFunc *) func_header_contains, 0 }, + { "user-tag", (ESExpFunc *) func_user_tag, 1 }, + { "user-flag", (ESExpFunc *) func_user_flag, 1 }, + { "get-sent-date", (ESExpFunc *) func_get_sent_date, 1 }, + { "get-received-date", (ESExpFunc *) func_get_received_date, 1 }, + { "get-current-date", (ESExpFunc *) func_get_current_date, 1 } +}; + char * imap_translate_sexp (const char *expression) { - struct sexp_node *root; - char *sexp, *exp; + ESExp *sexp; + ESExpResult *r; + gchar *retval; + GList *list = NULL; + int i; + + sexp = e_sexp_new (); + + for (i = 0; i < sizeof (symbols) / sizeof (symbols[0]); i++) { + if (symbols[i].type == 1) { + e_sexp_add_ifunction (sexp, 0, symbols[i].name, + (ESExpIFunc *)symbols[i].func, &list); + } else { + e_sexp_add_function (sexp, 0, symbols[i].name, + symbols[i].func, &list); + } + } + + e_sexp_input_text (sexp, expression, strlen (expression)); - exp = g_strdup (expression); - strip (exp, '\n'); - root = get_sexp_node (exp); - g_free (exp); + e_sexp_parse (sexp); - d(print_node (root, 0)); - d(fprintf (stderr, "\n")); + r = e_sexp_eval (sexp); - sexp = str_sexp_node (root); + gtk_object_unref (GTK_OBJECT (sexp)); + e_sexp_result_free (r); + + if (list->next) { + g_warning ("conversion to IMAP SEARCH string failed"); + retval = NULL; + g_list_foreach (list, (GFunc)g_free, NULL); + } else { + retval = list->data; + } - free_sexp_node (root); + g_list_free (list); - return sexp; + return retval; } -- cgit v1.2.3