From 3ef60c2537f654d15bed4347dbc12076be3064fc Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Mon, 31 Jul 2000 20:00:20 +0000 Subject: New convenience function to translate a Camel sexp into the equivalent 2000-07-31 Jeffrey Stedfast * providers/imap/camel-imap-utils.c (imap_translate_sexp): New convenience function to translate a Camel sexp into the equivalent IMAP sexp. * providers/imap/camel-imap-store.c: More places now use imap_next_word * providers/imap/camel-imap-folder.c (imap_search_by_expression): Implemented initial version (this may or may not work quite right) svn path=/trunk/; revision=4428 --- camel/providers/imap/camel-imap-folder.c | 60 ++++++-- camel/providers/imap/camel-imap-store.c | 69 +++++---- camel/providers/imap/camel-imap-utils.c | 243 +++++++++++++++++++++++++++++++ camel/providers/imap/camel-imap-utils.h | 2 + 4 files changed, 328 insertions(+), 46 deletions(-) (limited to 'camel/providers/imap') diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index 954e103c8f..2118482eac 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -272,7 +272,7 @@ imap_init (CamelFolder *folder, CamelStore *parent_store, CamelFolder *parent_fo folder->can_hold_messages = TRUE; folder->can_hold_folders = TRUE; folder->has_summary_capability = TRUE; - folder->has_search_capability = FALSE; /* FIXME: this should be TRUE 'cept it ain't implemented yet */ + folder->has_search_capability = TRUE; /* FIXME: this should be TRUE 'cept it ain't implemented yet */ /* some IMAP daemons support user-flags * * I would not, however, rely on this feature as * @@ -351,7 +351,7 @@ imap_expunge (CamelFolder *folder, CamelException *ex) { CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); gchar *node, *result; - gint i, status; + gint i, status, recent = -1; g_return_if_fail (folder != NULL); @@ -428,6 +428,10 @@ imap_expunge (CamelFolder *folder, CamelException *ex) /* Hopefully this should never happen */ d(fprintf (stderr, "imap expunge-error: message %d is out of range\n", id)); } + } else if (*word >= '0' && *word <= '9' && !strncmp ("RECENT", imap_next_word (word), 6)) { + recent = atoi (word); + if (!recent) + recent = -1; } } else { break; @@ -442,7 +446,7 @@ imap_expunge (CamelFolder *folder, CamelException *ex) /*imap_folder_summary_free (imap_folder);*/ - camel_imap_folder_changed (folder, -1, ex); + camel_imap_folder_changed (folder, recent, ex); } static gint @@ -1418,20 +1422,24 @@ imap_get_message_info (CamelFolder *folder, const char *uid) static GPtrArray * imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex) { - d(fprintf (stderr, "search expression: %s\n", expression)); - - return g_ptr_array_new (); -#if 0 /* NOTE: This is experimental code... */ - CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder); - char *result; + GPtrArray *uids = NULL; + char *result, *sexp; int status; - if (!imap_folder->has_search_capability) - return NULL; + d(fprintf (stderr, "camel sexp: '%s'\n", expression)); + sexp = imap_translate_sexp (expression); + d(fprintf (stderr, "imap sexp: '%s'\n", sexp)); + + uids = g_ptr_array_new (); + + if (!folder->has_search_capability) { + g_free (sexp); + return uids; + } status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, "SEARCH %s", expression); + &result, "SEARCH %s", sexp); if (status != CAMEL_IMAP_OK) { CamelService *service = CAMEL_SERVICE (folder->parent_store); @@ -1442,11 +1450,33 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc status != CAMEL_IMAP_FAIL && result ? result : "Unknown error"); g_free (result); - return NULL; + g_free (sexp); + return uids; } - /* now to parse @result */ -#endif + if (*result == '*' && !strncmp ("SEARCH", imap_next_word (result), 6)) { + char *word; + + word = imap_next_word (result); /* word now points to SEARCH */ + + for (word = imap_next_word (word); *word && *word != '*'; word = imap_next_word (word)) { + gboolean word_is_numeric = TRUE; + char *ep; + + /* find the end of this word and make sure it's a numeric uid */ + for (ep = word; *ep && *ep != ' ' && *ep != '\n'; ep++) + if (*ep < '0' || *ep > '9') + word_is_numeric = FALSE; + + if (word_is_numeric) + g_ptr_array_add (uids, g_strndup (word, (gint)(ep - word))); + } + } + + g_free (result); + g_free (sexp); + + return uids; } static guint32 diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index a46903d975..d3ba8f14f9 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -140,7 +140,7 @@ static void finalize (GtkObject *object) { CamelException ex; - + camel_exception_init (&ex); imap_disconnect (CAMEL_SERVICE (object), &ex); camel_exception_clear (&ex); @@ -148,10 +148,10 @@ finalize (GtkObject *object) static CamelServiceAuthType password_authtype = { "Password", - + "This option will connect to the IMAP server using a " "plaintext password.", - + "", TRUE }; @@ -162,26 +162,25 @@ try_connect (CamelService *service, CamelException *ex) struct hostent *h; struct sockaddr_in sin; gint fd; - + h = camel_service_gethost (service, ex); if (!h) return FALSE; - + sin.sin_family = h->h_addrtype; sin.sin_port = htons (service->url->port ? service->url->port : IMAP_PORT); memcpy (&sin.sin_addr, h->h_addr, sizeof (sin.sin_addr)); - + fd = socket (h->h_addrtype, SOCK_STREAM, 0); - if (fd == -1 || connect (fd, (struct sockaddr *)&sin, sizeof (sin)) == -1) { - + if (fd == -1 || connect (fd, (struct sockaddr *)&sin, sizeof (sin)) == -1) { /* We don't want to set a CamelException here */ - + if (fd > -1) close (fd); - + return FALSE; } - + close (fd); return TRUE; } @@ -191,24 +190,23 @@ query_auth_types (CamelService *service, CamelException *ex) { GList *ret = NULL; gboolean passwd = TRUE; - - + if (service->url) { passwd = try_connect (service, ex); if (camel_exception_get_id (ex) != CAMEL_EXCEPTION_NONE) return NULL; } - + if (passwd) ret = g_list_append (ret, &password_authtype); - + if (!ret) { camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "Could not connect to IMAP server on " - "%s.", service->url->host ? service->url->host : + "Could not connect to IMAP server on %s.", + service->url->host ? service->url->host : "(unknown host)"); } - + return ret; } @@ -750,15 +748,19 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, char **ret, char status = camel_imap_status (cmdid, respbuf); g_free (cmdid); - + if (ret) { - if (status != CAMEL_IMAP_FAIL) { - *ret = strchr (respbuf, ' '); - if (*ret) - *ret = g_strdup (*ret + 1); - } else + if (status != CAMEL_IMAP_FAIL && respbuf) { + char *word; + + word = imap_next_word (respbuf); /* word should now point to NO or BAD */ + + *ret = g_strdup (imap_next_word (word)); + } else { *ret = NULL; + } } + g_free (respbuf); return status; @@ -802,8 +804,8 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** GPtrArray *data; va_list app; int i; - -#if 0 + +#if 0 /* First make sure we're connected... */ if (!service->connected || !stream_is_alive (store->istream)) { CamelException *ex; @@ -821,7 +823,7 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** camel_exception_free (ex); } -#endif +#endif if (folder && store->current_folder != folder && strncmp (fmt, "CREATE", 6)) { /* We need to select the correct mailbox first */ @@ -886,7 +888,7 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** imap_disconnect (service, ex); camel_exception_free (ex); } -#endif +#endif break; } @@ -938,10 +940,15 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** } *p = '\0'; } else { - if (status != CAMEL_IMAP_FAIL && respbuf) - *ret = g_strdup (imap_next_word (respbuf)); - else + if (status != CAMEL_IMAP_FAIL && respbuf) { + char *word; + + word = imap_next_word (respbuf); /* word should now point to NO or BAD */ + + *ret = g_strdup (imap_next_word (word)); + } else { *ret = NULL; + } } for (i = 0; i < data->len; i++) diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c index 6560481505..08a45de62a 100644 --- a/camel/providers/imap/camel-imap-utils.c +++ b/camel/providers/imap/camel-imap-utils.c @@ -28,6 +28,19 @@ #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) { @@ -95,3 +108,233 @@ imap_parse_list_response (char *buf, char *namespace, char **flags, char **sep, return TRUE; } + +static char * +get_quoted_token (char *string, int *len) +{ + 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 char * +get_token (char *string, int *len) +{ + char *p, *ep; + + for (p = string; *p && *p == ' '; p++); + + if (*p == '"') { + char *token; + int i; + + token = get_quoted_token (p, &i); + + *len = i + (p - string); + + return token; + } + + for (ep = p; *ep && *ep != ' '; ep++); + + *len = ep - string; + + return g_strndup (p, *len); +} + +struct sexp_node * +get_sexp_node (const char *exp) +{ + 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; + + 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; + } +} + +static void +print_node (struct sexp_node *node, int depth) +{ + 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)); + } + + if (node->r_node) + print_node (node->r_node, depth + 1); + + if (node->l_node) + print_node (node->l_node, depth); +} + +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) +{ + 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; + } + + 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 void +free_sexp_node (struct sexp_node *node) +{ + if (node->r_node) + free_sexp_node (node->r_node); + + if (node->l_node) + free_sexp_node (node->l_node); + + g_free (node->data); + g_free (node); +} + +char * +imap_translate_sexp (const char *expression) +{ + struct sexp_node *root; + char *sexp; + + root = get_sexp_node (expression); + + d(print_node (root, 0)); + + sexp = str_sexp_node (root); + sexp[strlen (sexp) - 1] = '\0'; + strcpy (sexp, sexp + 1); + + free_sexp_node (root); + + return sexp; +} diff --git a/camel/providers/imap/camel-imap-utils.h b/camel/providers/imap/camel-imap-utils.h index 8ea5a40dbc..11c6c48956 100644 --- a/camel/providers/imap/camel-imap-utils.h +++ b/camel/providers/imap/camel-imap-utils.h @@ -34,6 +34,8 @@ char *imap_next_word (char *buf); gboolean imap_parse_list_response (char *buf, char *namespace, char **flags, char **sep, char **folder); +char *imap_translate_sexp (const char *expression); + #ifdef __cplusplus } #endif /* __cplusplus */ -- cgit v1.2.3