aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imap')
-rw-r--r--camel/providers/imap/camel-imap-folder.c60
-rw-r--r--camel/providers/imap/camel-imap-store.c69
-rw-r--r--camel/providers/imap/camel-imap-utils.c243
-rw-r--r--camel/providers/imap/camel-imap-utils.h2
4 files changed, 328 insertions, 46 deletions
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 */