aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-utils.c
diff options
context:
space:
mode:
authorJeffrey Stedfast <fejj@helixcode.com>2000-08-02 07:05:34 +0800
committerJeffrey Stedfast <fejj@src.gnome.org>2000-08-02 07:05:34 +0800
commit2c23afbef1edb9d907d3fd871876fe7cbe201d2f (patch)
treea9bf25d5d7518f27cbee5be9d5ef23bb49c88cbf /camel/providers/imap/camel-imap-utils.c
parentde528ac073b9e4cca654c41b75a34dbfce82d060 (diff)
downloadgsoc2013-evolution-2c23afbef1edb9d907d3fd871876fe7cbe201d2f.tar.gz
gsoc2013-evolution-2c23afbef1edb9d907d3fd871876fe7cbe201d2f.tar.zst
gsoc2013-evolution-2c23afbef1edb9d907d3fd871876fe7cbe201d2f.zip
New and improved sexp parser. An honest try at using e-sexp is wrapped in
2000-08-01 Jeffrey Stedfast <fejj@helixcode.com> * providers/imap/camel-imap-utils.c (imap_translate_sexp): New and improved sexp parser. An honest try at using e-sexp is wrapped in a #ifdef at the bottom of the file but is currently not used * providers/imap/camel-imap-folder.c (imap_search_by_expression): We want to do a UID SEARCH so we get UIDs back instead of sequence numbers svn path=/trunk/; revision=4461
Diffstat (limited to 'camel/providers/imap/camel-imap-utils.c')
-rw-r--r--camel/providers/imap/camel-imap-utils.c534
1 files changed, 313 insertions, 221 deletions
diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c
index af4cec0cb2..648201891b 100644
--- a/camel/providers/imap/camel-imap-utils.c
+++ b/camel/providers/imap/camel-imap-utils.c
@@ -30,6 +30,25 @@
#define d(x) x
+static char *esexp_keys[] = { "and", "or", "body-contains", "header-contains", "match-all", NULL };
+static char *imap_keys[] = { "", "OR", "BODY", "HEADER", 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 *
imap_next_word (char *buf)
{
@@ -98,289 +117,362 @@ imap_parse_list_response (char *buf, char *namespace, char **flags, char **sep,
return TRUE;
}
-struct prop_info {
- char *query_prop;
- char *imap_attr;
-} prop_info_table[] = {
- /* query prop, imap attr */
- { "body-contains", "BODY" },
- { "header-contains", "HEADER" }
-};
-
-static int num_prop_infos = sizeof (prop_info_table) / sizeof (prop_info_table[0]);
-
-static gchar *
-query_prop_to_imap (gchar *query_prop)
+static char *
+get_quoted_token (char *string, int *len)
{
- int i;
-
- for (i = 0; i < num_prop_infos; i ++)
- if (!strcmp (query_prop, prop_info_table[i].query_prop))
- return prop_info_table[i].imap_attr;
-
- return NULL;
+ char *ep;
+
+ for (ep = string + 1; *ep; ep++)
+ if (*ep == '"' && *(ep - 1) != '\\')
+ break;
+ if (*ep)
+ ep++;
+
+ *len = ep - string;
+
+ return g_strndup (string, *len);
}
-static ESExpResult *
-func_and (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+static char *
+get_token (char *string, int *len)
{
- GList **list = data;
- ESExpResult *r;
- char **strings;
+ char *p, *ep;
- if (argc > 0) {
+ for (p = string; *p && *p == ' '; p++);
+
+ if (*p == '"') {
+ char *token;
int i;
+
+ token = get_quoted_token (p, &i);
+
+ *len = i + (p - string);
- strings = g_malloc0 (argc + 3);
- strings[0] = g_strdup ("(AND");
- strings[argc+3 - 2] = g_strdup (")");
- strings[argc+3 - 1] = NULL;
-
- for (i = 0; i < argc; i++) {
- GList *list_head = *list;
- strings[argc - i] = (*list)->data;
- *list = g_list_remove_link (*list, *list);
- g_list_free_1 (list_head);
- }
-
- *list = g_list_prepend (*list, g_strjoinv (" ", strings));
-
- for (i = 0 ; i < argc + 2; i++)
- g_free (strings[i]);
-
- g_free (strings);
+ return token;
}
- r = e_sexp_result_new (ESEXP_RES_BOOL);
- r->value.bool = FALSE;
+ for (ep = p; *ep && *ep != ' ' && *ep != ')'; ep++);
+
+ *len = ep - string;
- return r;
+ return g_strndup (p, *len);
}
-static ESExpResult *
-func_or (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+struct sexp_node *
+get_sexp_node (const char *exp)
{
- GList **list = data;
- ESExpResult *r;
- char **strings;
-
- if (argc > 0) {
- int i;
+ 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;
- strings = g_malloc0 (argc+3);
- strings[0] = g_strdup ("(OR");
- strings[argc+3 - 2] = g_strdup (")");
- strings[argc+3 - 1] = NULL;
- for (i = 0; i < argc; i++) {
- GList *list_head = *list;
- strings[argc - i] = (*list)->data;
- *list = g_list_remove_link (*list, *list);
- g_list_free_1 (list_head);
+ p = (char *) exp + 1;
+ for (ep = p, pbal = 1; *ep && pbal; ep++) {
+ if (*ep == '(')
+ pbal++;
+ if (*ep == ')')
+ pbal--;
}
- *list = g_list_prepend (*list, g_strjoinv (" ", strings));
+ this_exp = g_strndup (p, (gint)(ep - p));
+
+ for (left_exp = ep; *left_exp && *left_exp != '('; left_exp++);
+ left_exp = g_strdup (left_exp);
- for (i = 0 ; i < argc + 2; 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--;
+ }
+ right_exp = g_strndup (right_exp, (gint)(ep - right_exp));
- g_free (strings);
+ /* 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));
+
+ g_strstrip (node->data);
+
+ node->l_node = get_sexp_node (left_exp);
+ node->r_node = get_sexp_node (right_exp);
+
+ g_free (this_exp);
+ g_free (left_exp);
+ g_free (right_exp);
}
- r = e_sexp_result_new (ESEXP_RES_BOOL);
- r->value.bool = FALSE;
-
- return r;
+ return node;
}
-static ESExpResult *
-func_not (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+static void
+print_node (struct sexp_node *node, int depth)
{
- GList **list = data;
- ESExpResult *r;
-
- /* 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);
- g_free (term);
+ int i;
+
+ for (i = 0; i < depth; i++)
+ d(fprintf (stderr, " "));
+
+ d(fprintf (stderr, "%s\n", node->function));
+
+ if (*node->data) {
+ for (i = 0; i < depth + 1; i++)
+ d(fprintf (stderr, " "));
+
+ d(fprintf (stderr, "%s\n", node->data));
}
- r = e_sexp_result_new (ESEXP_RES_BOOL);
- r->value.bool = FALSE;
+ if (node->r_node)
+ print_node (node->r_node, depth + 1);
- return r;
+ if (node->l_node)
+ print_node (node->l_node, depth);
}
-static ESExpResult *
-func_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+static const char *
+get_func (struct sexp_node *node)
{
- GList **list = data;
- ESExpResult *r;
-
- if (argc == 2
- && argv[0]->type == ESEXP_RES_STRING
- && argv[1]->type == ESEXP_RES_STRING) {
- char *propname = argv[0]->value.string;
- char *str = argv[1]->value.string;
- char *imap_attr = query_prop_to_imap (propname);
- gboolean one_star = FALSE;
-
- if (strlen (str) == 0)
- one_star = TRUE;
-
- if (imap_attr)
- *list = g_list_prepend (*list,
- g_strdup_printf ("(%s=*%s%s)",
- imap_attr,
- str,
- one_star ? "" : "*"));
- }
+ int i;
- r = e_sexp_result_new (ESEXP_RES_BOOL);
- r->value.bool = FALSE;
+ for (i = 0; esexp_keys[i]; i++)
+ if (!strncmp (esexp_keys[i], node->function, strlen (node->function)))
+ break;
- return r;
+ if (esexp_keys[i])
+ return imap_keys[i];
+ else
+ return node->function;
}
-static ESExpResult *
-func_is (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+static char *
+get_data (struct sexp_node *node)
{
- GList **list = data;
- ESExpResult *r;
-
- if (argc == 2
- && argv[0]->type == ESEXP_RES_STRING
- && argv[1]->type == ESEXP_RES_STRING) {
- char *propname = argv[0]->value.string;
- char *str = argv[1]->value.string;
- char *imap_attr = query_prop_to_imap (propname);
-
- if (imap_attr)
- *list = g_list_prepend (*list,
- g_strdup_printf ("(%s=%s)",
- imap_attr, str));
+ GPtrArray *args;
+ const char *func;
+ char *data, *token, *p;
+ int i, len;
+
+ func = get_func (node);
+
+ args = g_ptr_array_new ();
+
+ p = node->data;
+ while (p && *p) {
+ token = get_token (p, &len);
+ g_ptr_array_add (args, token);
+ p += len;
}
- r = e_sexp_result_new (ESEXP_RES_BOOL);
- r->value.bool = FALSE;
+ if (func && !strcmp ("HEADER", func) && args->len > 0)
+ string_unquote (args->pdata[0]);
+
+ if (args->len > 0) {
+ data = g_strjoinv (" ", (char **) args->pdata);
+ } else {
+ data = g_strdup ("");
+ }
- return r;
+ for (i = 0; i < args->len; i++)
+ g_free (args->pdata[i]);
+
+ g_ptr_array_free (args, TRUE);
+
+ return data;
}
-static ESExpResult *
-func_beginswith (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+static char *
+str_sexp_node (struct sexp_node *node)
{
- GList **list = data;
- ESExpResult *r;
-
- if (argc == 2
- && argv[0]->type == ESEXP_RES_STRING
- && argv[1]->type == ESEXP_RES_STRING) {
- char *propname = argv[0]->value.string;
- char *str = argv[1]->value.string;
- char *imap_attr = query_prop_to_imap (propname);
- gboolean one_star = FALSE;
-
- if (strlen(str) == 0)
- one_star = TRUE;
-
- if (imap_attr)
- *list = g_list_prepend (*list,
- g_strdup_printf ("(%s=%s*)",
- imap_attr,
- str));
+ char *node_str, *data, *str, *l_str, *r_str;
+ const char *func;
+
+ func = get_func (node);
+ data = get_data (node);
+
+ if (func) {
+ if (*data)
+ str = g_strdup_printf ("%s %s", func, data);
+ else
+ str = g_strdup (func);
+ } else {
+ str = NULL;
}
- r = e_sexp_result_new (ESEXP_RES_BOOL);
- r->value.bool = FALSE;
-
- return r;
+ g_free (data);
+
+ r_str = NULL;
+ if (node->r_node)
+ r_str = str_sexp_node (node->r_node);
+
+ l_str = NULL;
+ if (node->l_node)
+ l_str = str_sexp_node (node->l_node);
+
+ 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 ("");
+ }
+ }
+
+ g_free (str);
+ g_free (l_str);
+ g_free (r_str);
+
+ return node_str;
}
-static ESExpResult *
-func_endswith (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data)
+static void
+free_sexp_node (struct sexp_node *node)
{
- GList **list = data;
- ESExpResult *r;
-
- if (argc == 2
- && argv[0]->type == ESEXP_RES_STRING
- && argv[1]->type == ESEXP_RES_STRING) {
- char *propname = argv[0]->value.string;
- char *str = argv[1]->value.string;
- char *imap_attr = query_prop_to_imap (propname);
- gboolean one_star = FALSE;
-
- if (strlen (str) == 0)
- one_star = TRUE;
-
- if (imap_attr)
- *list = g_list_prepend (*list,
- g_strdup_printf ("(%s=*%s)",
- imap_attr,
- str));
- }
+ if (node->r_node)
+ free_sexp_node (node->r_node);
- r = e_sexp_result_new(ESEXP_RES_BOOL);
- r->value.bool = FALSE;
+ if (node->l_node)
+ free_sexp_node (node->l_node);
- return r;
+ g_free (node->function);
+ g_free (node->data);
+ g_free (node);
}
-/* '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", func_and, 0 },
- { "or", func_or, 0 },
- { "not", func_not, 0 },
- { "contains", func_contains, 0 },
- { "is", func_is, 0 },
- { "beginswith", func_beginswith, 0 },
- { "endswith", func_endswith, 0 },
-};
-
char *
imap_translate_sexp (const char *expression)
{
- ESExp *sexp;
- ESExpResult *r;
- gchar *retval;
- GList *list = NULL;
+ struct sexp_node *root;
+ char *sexp;
+
+ root = get_sexp_node (expression);
+
+ d(print_node (root, 0));
+ d(fprintf (stderr, "\n"));
+
+ sexp = str_sexp_node (root);
+
+ free_sexp_node (root);
+
+ return sexp;
+}
+
+
+
+
+
+
+
+
+
+
+#ifdef _ALL_HELL_BROKE_LOOSE_
+static char *
+stresexptree (ESExpTerm *node)
+{
+ char *node_str, *func, *str, *l_str, *r_str;
int i;
- sexp = e_sexp_new ();
+ for (i = 0; esexp_keys[i]; i++)
+ if (!strncmp (esexp_keys[i], node->func->sym->name, strlen (node->func->sym->name)))
+ break;
+
+ if (esexp_keys[i])
+ func = imap_keys[i];
+ else
+ func = node->func->sym->name;
+
+ if (func) {
+ if (*node->var->name)
+ str = g_strdup_printf ("%s %s", func, node->var->name);
+ else
+ str = g_strdup (func);
+ } else {
+ str = NULL;
+ }
+
+ r_str = NULL;
+ if (node->r_node)
+ r_str = str_sexp_node (node->r_node);
+
+ l_str = NULL;
+ if (node->l_node)
+ l_str = str_sexp_node (node->l_node);
- 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);
+ 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 {
- e_sexp_add_function (sexp, 0, symbols[i].name,
- symbols[i].func, &list);
+ 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 ("");
}
}
- e_sexp_input_text (sexp, expression, strlen (expression));
- e_sexp_parse (sexp);
+ g_free (str);
+ g_free (l_str);
+ g_free (r_str);
- r = e_sexp_eval (sexp);
+ return node_str;
+}
+
+char *
+imap_translate_sexp (const char *expression)
+{
+ ESExp *esexp;
+ char *sexp;
- gtk_object_unref (GTK_OBJECT (sexp));
- e_sexp_result_free (r);
+ esexp = e_sexp_new ();
- if (list->next) {
- g_warning ("conversion to imap expression string failed");
- retval = NULL;
- g_list_foreach (list, (GFunc)g_free, NULL);
- } else {
- retval = list->data;
- }
+ e_sexp_input_text (esexp, expression, strlen (expression));
+ e_sexp_parse (esexp);
+
+ sexp = stresexptree (esexp->tree);
- g_list_free (list);
+ gtk_object_unref (GTK_OBJECT (esexp));
- return retval;
+ return sexp;
}
+#endif /* _ALL_HELL_BROKE_LOOSE_ */