diff options
Diffstat (limited to 'camel')
-rw-r--r-- | camel/ChangeLog | 4 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-folder.c | 36 | ||||
-rw-r--r-- | camel/providers/imap/camel-imap-utils.c | 425 |
3 files changed, 257 insertions, 208 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog index ab022c1d10..ee2cd43dd5 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,5 +1,9 @@ 2000-07-31 Jeffrey Stedfast <fejj@helixcode.com> + * providers/imap/camel-imap-folder.c (imap_get_message_info_internal): + Some IMAP servers don't wrap the UID in ()'s so don't depend on that + (imap_get_summary_internal): Same + * providers/imap/camel-imap-utils.c (free_sexp_node): Oops, forgot to free node->function - not good. diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 2118482eac..3dafa48451 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -1150,17 +1150,17 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) info = g_malloc0 (sizeof (CamelMessageInfo)); /* lets grab the UID... */ - if (!(uid = strstr (headers->pdata[i], "(UID "))) { + if (!(uid = strstr (headers->pdata[i], "UID "))) { d(fprintf (stderr, "Cannot get a uid for %d\n\n%s\n\n", i+1, (char *) headers->pdata[i])); g_free (info); break; } - for (uid += 5; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to <uid> */ + for (uid += 4; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to <uid> */ for (q = uid; *q && *q >= '0' && *q <= '9'; q++); /* find the end of the <uid> */ info->uid = g_strndup (uid, (gint)(q - uid)); d(fprintf (stderr, "*** info->uid = %s\n", info->uid)); - + /* now lets grab the FLAGS */ if (!(flags = strstr (q, "FLAGS "))) { d(fprintf (stderr, "We didn't seem to get any flags for %d...\n", i)); @@ -1168,12 +1168,12 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) g_free (info); break; } - + for (flags += 6; *flags && *flags != '('; flags++); /* advance to <flags> */ for (q = flags; *q && *q != ')'; q++); /* find the end of <flags> */ flags = g_strndup (flags, (gint)(q - flags + 1)); d(fprintf (stderr, "*** info->flags = %s\n", flags)); - + /* now we gotta parse for the flags */ info->flags = 0; if (strstr (flags, "\\Seen")) @@ -1196,7 +1196,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) for (j = 0; *header_fields[j]; j++) { struct _header_raw *raw; char *field, *value; - + field = g_strdup_printf ("\n%s:", header_fields[j]); value = get_header_field (header, field); g_free (field); @@ -1208,7 +1208,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) raw->name = g_strdup (header_fields[j]); raw->value = value; raw->offset = -1; - + if (!h) { h = raw; tail = h; @@ -1217,7 +1217,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) tail = raw; } } - + /* construct the CamelMessageInfo */ info->subject = camel_summary_format_string (h, "subject"); info->from = camel_summary_format_address (h, "from"); @@ -1238,7 +1238,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) info->references = header_references_decode (header_raw_find (&h, "references", NULL)); if (info->references == NULL) info->references = header_references_decode (header_raw_find (&h, "in-reply-to", NULL)); - + while (h->next) { struct _header_raw *next = h->next; @@ -1247,15 +1247,15 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) g_free (h); h = next; } - + g_ptr_array_add (summary, info); g_hash_table_insert (hash, info->uid, info); } - + for (i = 0; i < headers->len; i++) g_free (headers->pdata[i]); g_ptr_array_free (headers, TRUE); - + /* clean up any previous summary data */ imap_folder_summary_free (imap_folder); @@ -1298,13 +1298,13 @@ imap_get_message_info_internal (CamelFolder *folder, guint id) } /* lets grab the UID... */ - if (!(uid = (char *) e_strstrcase (result, "(UID "))) { + if (!(uid = (char *) e_strstrcase (result, "UID "))) { d(fprintf (stderr, "Cannot get a uid for %d\n\n%s\n\n", id, result)); g_free (result); return NULL; } - for (uid += 5; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to <uid> */ + for (uid += 4; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to <uid> */ for (q = uid; *q && *q >= '0' && *q <= '9'; q++); /* find the end of the <uid> */ uid = g_strndup (uid, (gint)(q - uid)); @@ -1424,7 +1424,7 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc { /* NOTE: This is experimental code... */ GPtrArray *uids = NULL; - char *result, *sexp; + char *result, *sexp, *p; int status; d(fprintf (stderr, "camel sexp: '%s'\n", expression)); @@ -1453,11 +1453,11 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc g_free (sexp); return uids; } - - if (*result == '*' && !strncmp ("SEARCH", imap_next_word (result), 6)) { + + if ((p = strstr (result, "* SEARCH"))) { char *word; - word = imap_next_word (result); /* word now points to SEARCH */ + word = imap_next_word (p); /* word now points to SEARCH */ for (word = imap_next_word (word); *word && *word != '*'; word = imap_next_word (word)) { gboolean word_is_numeric = TRUE; diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c index 954defabc5..af4cec0cb2 100644 --- a/camel/providers/imap/camel-imap-utils.c +++ b/camel/providers/imap/camel-imap-utils.c @@ -23,24 +23,13 @@ #include <stdio.h> #include <string.h> +#include <gtk/gtk.h> #include "camel-imap-utils.h" #include "string-utils.h" +#include <e-sexp.h> #define d(x) x -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 char *str_sexp_node (struct sexp_node *node); -static void free_sexp_node (struct sexp_node *node); - char * imap_next_word (char *buf) { @@ -109,233 +98,289 @@ imap_parse_list_response (char *buf, char *namespace, char **flags, char **sep, return TRUE; } -static char * -get_quoted_token (char *string, int *len) +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) { - char *ep; - - for (ep = string + 1; *ep; ep++) - if (*ep == '"' && *(ep - 1) != '\\') - break; - if (*ep) - ep++; - - *len = ep - string; - - return g_strndup (string, *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; } -static char * -get_token (char *string, int *len) +static ESExpResult * +func_and (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - char *p, *ep; + GList **list = data; + ESExpResult *r; + char **strings; - for (p = string; *p && *p == ' '; p++); - - if (*p == '"') { - char *token; + if (argc > 0) { int i; - token = get_quoted_token (p, &i); + strings = g_malloc0 (argc + 3); + strings[0] = g_strdup ("(AND"); + strings[argc+3 - 2] = g_strdup (")"); + strings[argc+3 - 1] = NULL; - *len = i + (p - string); + 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); + } - return token; + *list = g_list_prepend (*list, g_strjoinv (" ", strings)); + + for (i = 0 ; i < argc + 2; i++) + g_free (strings[i]); + + g_free (strings); } - for (ep = p; *ep && *ep != ' '; ep++); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - *len = ep - string; - - return g_strndup (p, *len); + return r; } -struct sexp_node * -get_sexp_node (const char *exp) +static ESExpResult * +func_or (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - struct sexp_node *node = NULL; - char *p, *ep; - int len; - - switch (*exp) { - case '(': - node = g_malloc0 (sizeof (struct sexp_node)); - node->l_node = NULL; - node->r_node = NULL; - node->data = NULL; - - p = (char *) exp + 1; - - node->function = get_token (p, &len); - - p += len; - for (ep = p; *ep && *ep != '(' && *ep != ')'; ep++); - node->data = g_strndup (p, (gint)(ep - p)); - g_strstrip (node->data); - - p = ep; - - if (*p == '(') - node->r_node = get_sexp_node (p); - else - node->l_node = get_sexp_node (p); - - return node; - break; - case '\0': - return NULL; - break; - case ')': - for (p = (char *) exp + 1; *p && *p == ' '; p++); - return get_sexp_node (p); - break; - default: - node = g_malloc0 (sizeof (struct sexp_node)); - node->l_node = NULL; - node->r_node = NULL; - node->data = NULL; - - p = (char *) exp; + GList **list = data; + ESExpResult *r; + char **strings; + + if (argc > 0) { + int i; - node->function = get_token (p, &len); - - p += len; - for (ep = p; *ep && *ep != '(' && *ep != ')'; ep++); - node->data = g_strndup (p, (gint)(ep - p)); - g_strstrip (node->data); + 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 = ep; + *list = g_list_prepend (*list, g_strjoinv (" ", strings)); - if (*p == '(') - node->r_node = get_sexp_node (p); - else - node->l_node = get_sexp_node (p); + for (i = 0 ; i < argc + 2; i++) + g_free (strings[i]); - return node; + g_free (strings); } + + 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 ESExpResult * +func_not (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - int i; - - for (i = 0; i < depth; i++) - d(fprintf (stderr, " ")); + 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); + } - d(fprintf (stderr, "%s\n", node->function)); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - if (*node->data) { - for (i = 0; i < depth + 1; i++) - d(fprintf (stderr, " ")); + return r; +} + +static ESExpResult * +func_contains (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + 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; - d(fprintf (stderr, "%s\n", node->data)); + 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 ? "" : "*")); } - 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 char *esexp_keys[] = { "or", "body-contains", "header-contains", "match-all", NULL }; -static char *imap_keys[] = { "OR", "BODY", "HEADER", NULL }; - -static char * -str_sexp_node (struct sexp_node *node) +static ESExpResult * +func_is (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - char *node_str, *func, *str, *l_str, *r_str; - int i; - - for (i = 0; esexp_keys[i]; i++) - if (!strncmp (esexp_keys[i], node->function, strlen (node->function))) - break; - - if (esexp_keys[i]) - func = imap_keys[i]; - else - func = node->function; - - if (func) { - if (*node->data) - str = g_strdup_printf ("%s %s", func, node->data); - else - str = g_strdup (func); - } else { - str = NULL; + 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)); } - 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); + r = e_sexp_result_new (ESEXP_RES_BOOL); + r->value.bool = FALSE; - 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 (""); - } + return r; +} + +static ESExpResult * +func_beginswith (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) +{ + 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)); } - 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_endswith (struct _ESExp *f, int argc, struct _ESExpResult **argv, void *data) { - if (node->r_node) - free_sexp_node (node->r_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->l_node) - free_sexp_node (node->l_node); - - g_free (node->function); - g_free (node->data); - g_free (node); + r = e_sexp_result_new(ESEXP_RES_BOOL); + r->value.bool = FALSE; + + 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", 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) { - struct sexp_node *root; - char *sexp; + ESExp *sexp; + ESExpResult *r; + gchar *retval; + GList *list = NULL; + int i; - root = get_sexp_node (expression); + sexp = e_sexp_new (); - d(print_node (root, 0)); + 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)); + e_sexp_parse (sexp); - sexp = str_sexp_node (root); - sexp[strlen (sexp) - 1] = '\0'; - strcpy (sexp, sexp + 1); + r = e_sexp_eval (sexp); + + gtk_object_unref (GTK_OBJECT (sexp)); + e_sexp_result_free (r); + + 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; + } - free_sexp_node (root); + g_list_free (list); - return sexp; + return retval; } |