From 151fb928c3191fbf37d34e0f35ff242587fbb307 Mon Sep 17 00:00:00 2001 From: Jeffrey Stedfast Date: Wed, 30 Aug 2000 21:01:59 +0000 Subject: [PATCH] Don't wrap printed strings in quotes, makes things messy 2000-08-30 Jeffrey Stedfast * camel-remote-store.c (remote_send_string): Don't wrap printed strings in quotes, makes things messy * providers/imap/camel-imap-folder.c (imap_get_message): Updated to use the camel_imap_fetch_command * providers/imap/camel-imap-stream.c (stream_read): Updated to use camel_imap_fetch_command * providers/imap/camel-imap-store.c (camel_imap_command_extended): No longer handles FETCH requests so no longer needs to be concerned with checking to make sure that server responses are valid (they have to be). (camel_imap_fetch_command): New convenience function that handles all FETCH requests svn path=/trunk/; revision=5122 --- camel/ChangeLog | 18 + camel/camel-remote-store.c | 2 +- camel/providers/imap/camel-imap-folder.c | 18 +- camel/providers/imap/camel-imap-store.c | 575 +++++++++++++++++------ camel/providers/imap/camel-imap-store.h | 3 + camel/providers/imap/camel-imap-stream.c | 8 +- 6 files changed, 471 insertions(+), 153 deletions(-) diff --git a/camel/ChangeLog b/camel/ChangeLog index f272ee4293..b72bd0cf62 100644 --- a/camel/ChangeLog +++ b/camel/ChangeLog @@ -1,3 +1,21 @@ +2000-08-30 Jeffrey Stedfast + + * camel-remote-store.c (remote_send_string): Don't wrap printed + strings in quotes, makes things messy + + * providers/imap/camel-imap-folder.c (imap_get_message): Updated + to use the camel_imap_fetch_command + + * providers/imap/camel-imap-stream.c (stream_read): Updated to use + camel_imap_fetch_command + + * providers/imap/camel-imap-store.c (camel_imap_command_extended): + No longer handles FETCH requests so no longer needs to be + concerned with checking to make sure that server responses are + valid (they have to be). + (camel_imap_fetch_command): New convenience function that handles + all FETCH requests + 2000-08-30 Peter Williams * camel-remote-store.c (remote_connect): Unify with remote_post_connect. diff --git a/camel/camel-remote-store.c b/camel/camel-remote-store.c index 5105045104..d11fd0bcbd 100644 --- a/camel/camel-remote-store.c +++ b/camel/camel-remote-store.c @@ -334,7 +334,7 @@ remote_send_string (CamelRemoteStore *store, CamelException *ex, char *fmt, va_l /* create the command */ cmdbuf = g_strdup_vprintf (fmt, ap); - d(fprintf (stderr, "sending : \"%s\"\n", cmdbuf)); + d(fprintf (stderr, "sending : %s", cmdbuf)); if (camel_stream_printf (store->ostream, "%s", cmdbuf) == -1) { CamelException dex; diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c index ce15fd7e97..5744a61584 100644 --- a/camel/providers/imap/camel-imap-folder.c +++ b/camel/providers/imap/camel-imap-folder.c @@ -802,9 +802,9 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex) else data_item = "RFC822.HEADER"; - status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, ex, "UID FETCH %s %s", uid, - data_item); + status = camel_imap_fetch_command (CAMEL_IMAP_STORE (folder->parent_store), folder, + &result, ex, "UID FETCH %s %s", uid, + data_item); if (!result || status != CAMEL_IMAP_OK) return NULL; @@ -855,9 +855,9 @@ imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex) else data_item = "RFC822.TEXT"; - status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, - &result, ex, "UID FETCH %s %s", uid, - data_item); + status = camel_imap_fetch_command (CAMEL_IMAP_STORE (folder->parent_store), folder, + &result, ex, "UID FETCH %s %s", uid, + data_item); if (!result || status != CAMEL_IMAP_OK) { g_free (header); @@ -1024,6 +1024,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) summary_specifier = imap_protocol_get_summary_specifier (folder); + /* We use camel_imap_command_extended here because it's safe */ if (num == 1) { status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, &result, ex, "FETCH 1 (%s)", summary_specifier); @@ -1083,7 +1084,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) for (uid += 4; *uid && (*uid < '0' || *uid > '9'); uid++); /* advance to */ for (q = uid; *q && *q >= '0' && *q <= '9'; q++); /* find the end of the */ info->uid = g_strndup (uid, (gint)(q - uid)); - d(fprintf (stderr, "*** info->uid = %s\n", info->uid)); + /*d(fprintf (stderr, "*** info->uid = %s\n", info->uid));*/ /* now lets grab the FLAGS */ if (!(flags = strstr (headers->pdata[i], "FLAGS "))) { @@ -1096,7 +1097,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex) for (flags += 6; *flags && *flags != '('; flags++); /* advance to */ for (q = flags; *q && *q != ')'; q++); /* find the end of */ flags = g_strndup (flags, (gint)(q - flags + 1)); - d(fprintf (stderr, "*** info->flags = %s\n", flags)); + /*d(fprintf (stderr, "*** info->flags = %s\n", flags));*/ /* now we gotta parse for the flags */ info->flags = 0; @@ -1211,6 +1212,7 @@ imap_get_message_info_internal (CamelFolder *folder, guint id, CamelException *e /* we don't have a cached copy, so fetch it */ summary_specifier = imap_protocol_get_summary_specifier (folder); + /* again, we use camel_imap_command_extended here because it's safe to do so */ status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, &result, ex, "FETCH %d (%s)", id, summary_specifier); diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c index c3b859c47e..98cfd9095f 100644 --- a/camel/providers/imap/camel-imap-store.c +++ b/camel/providers/imap/camel-imap-store.c @@ -181,7 +181,7 @@ imap_connect (CamelService *service, CamelException *ex) if (CAMEL_SERVICE_CLASS (remote_store_class)->connect (service, ex) == FALSE) return FALSE; - + store->command = 0; g_free (store->dir_sep); store->dir_sep = g_strdup ("/"); /* default dir sep */ @@ -524,7 +524,7 @@ check_current_folder (CamelImapStore *store, CamelFolder *folder, char *fmt, Cam * 1. the command doesn't care about which folder we're in (folder == NULL) * 2. if we're already in the right folder (store->current_folder == folder) * 3. we're going to create a new folder */ - if (!folder || store->current_folder == folder || !strncmp (fmt, "CREATE", 5)) + if (!folder || store->current_folder == folder || !strncmp (fmt, "CREATE ", 7)) return CAMEL_IMAP_OK; dir_sep = store->dir_sep; @@ -569,139 +569,6 @@ send_command (CamelImapStore *store, char **cmdid, char *fmt, va_list ap, CamelE return TRUE; } -static gint -slurp_response (CamelImapStore *store, CamelFolder *folder, char *cmdid, char **ret, - gboolean stop_on_plus, CamelException *ex) -{ - gint status = CAMEL_IMAP_OK; - GPtrArray *data, *expunged; - gchar *respbuf; - guint32 len = 0; - gint recent = 0; - gint i; - - data = g_ptr_array_new (); - expunged = g_ptr_array_new (); - - while (1) { - if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) { - for (i = 0; i < data->len; i++) - g_free (data->pdata[i]); - g_ptr_array_free (data, TRUE); - g_ptr_array_free (expunged, TRUE); - - return CAMEL_IMAP_FAIL; - } - - g_ptr_array_add (data, respbuf); - len += strlen (respbuf) + 1; - - /* IMAP's last response starts with our command id or, sometimes, a plus */ - if (stop_on_plus && *respbuf == '+') { - status = CAMEL_IMAP_PLUS; - break; - } - - if (!strncmp (respbuf, cmdid, strlen (cmdid))) { - status = camel_imap_status (cmdid, respbuf); - break; - } - - /* If recent or expunge flags were somehow set and this - response doesn't begin with a '*' then - recent/expunged must have been misdetected */ - if ((recent || expunged->len > 0) && *respbuf != '*') { - d(fprintf (stderr, "hmmm, someone tried to pull a fast one on us.\n")); - - recent = 0; - - for (i = 0; i < expunged->len; i++) { - g_free (expunged->pdata[i]); - g_ptr_array_remove_index (expunged, i); - } - } - - /* Check for a RECENT in the untagged response */ - if (*respbuf == '*') { - if (strstr (respbuf, "RECENT")) { - char *rcnt; - - d(fprintf (stderr, "*** We may have found a 'RECENT' flag: %s\n", respbuf)); - /* Make sure it's in the form: "* %d RECENT" */ - rcnt = imap_next_word (respbuf); - if (*rcnt >= '0' && *rcnt <= '9' && !strncmp ("RECENT", imap_next_word (rcnt), 6)) - recent = atoi (rcnt); - } else if (strstr (respbuf, "EXPUNGE")) { - char *id_str; - int id; - - d(fprintf (stderr, "*** We may have found an 'EXPUNGE' flag: %s\n", respbuf)); - /* Make sure it's in the form: "* %d EXPUNGE" */ - id_str = imap_next_word (respbuf); - if (*id_str >= '0' && *id_str <= '9' && !strncmp ("EXPUNGE", imap_next_word (id_str), 7)) { - id = atoi (id_str); - g_ptr_array_add (expunged, g_strdup_printf ("%d", id)); - } - } - } - } - - /* Apply the 'recent' changes */ - if (folder && recent > 0) - camel_imap_folder_changed (folder, recent, expunged, ex); - - if (status == CAMEL_IMAP_OK || status == CAMEL_IMAP_PLUS) { - gchar *p; - - /* Command succeeded! Put the output into one big - * string of love. */ - - *ret = g_new (char, len + 1); - p = *ret; - - for (i = 0; i < data->len; i++) { - char *datap; - - datap = (char *) data->pdata[i]; - if (*datap == '.') - datap++; - len = strlen (datap); - memcpy (p, datap, len); - p += len; - *p++ = '\n'; - } - - *p = '\0'; - } else { - /* Bummer. Try to grab what the server said. */ - if (respbuf) { - char *word; - - word = imap_next_word (respbuf); /* should now point to status */ - - word = imap_next_word (word); /* points to fail message, if there is one */ - - camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, - "IMAP command failed: %s", word); - } - - *ret = NULL; - } - - /* Can this be put into the 'if succeeded' bit? - * Or can a failed command generate untagged responses? */ - - for (i = 0; i < data->len; i++) - g_free (data->pdata[i]); - g_ptr_array_free (data, TRUE); - - for (i = 0; i < expunged->len; i++) - g_free (expunged->pdata[i]); - g_ptr_array_free (expunged, TRUE); - - return status; -} - /** * camel_imap_command: Send a command to a IMAP server. @@ -792,7 +659,7 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, CamelException * * be set to NULL.) The caller function is responsible for freeing @ret. * * This camel method gets the additional data returned by "multi-line" IMAP - * commands, such as SELECT, LIST, FETCH, and various other commands. + * commands, such as SELECT, LIST, and various other commands. * The returned data is un-byte-stuffed, and has lines termined by * newlines rather than CR/LF pairs. * @@ -806,8 +673,12 @@ gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...) { gint status = CAMEL_IMAP_OK; - gchar *cmdid; + GPtrArray *data, *expunged; + gchar *respbuf, *cmdid; + guint32 len = 0; + gint recent = 0; va_list ap; + gint i; status = check_current_folder (store, folder, fmt, ex); if (status != CAMEL_IMAP_OK) @@ -821,7 +692,284 @@ camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char ** } va_end (ap); - return slurp_response (store, folder, cmdid, ret, FALSE, ex); + data = g_ptr_array_new (); + expunged = g_ptr_array_new (); + + /* read multi-line response */ + while (1) { + if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) { + /* cleanup */ + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + for (i = 0; i < expunged->len; i++) + g_free (expunged->pdata[i]); + g_ptr_array_free (expunged, TRUE); + + return CAMEL_IMAP_FAIL; + } + + g_ptr_array_add (data, respbuf); + len += strlen (respbuf) + 1; + + /* IMAPs multi-line response ends with the cmdid string at the beginning of the line */ + if (!strncmp (respbuf, cmdid, strlen (cmdid))) { + status = camel_imap_status (cmdid, respbuf); + break; + } + + /* Check for a RECENT in the untagged response */ + if (*respbuf == '*') { + if (strstr (respbuf, "RECENT")) { + char *rcnt; + + d(fprintf (stderr, "*** We may have found a 'RECENT' flag: %s\n", respbuf)); + /* Make sure it's in the form: "* %d RECENT" */ + rcnt = imap_next_word (respbuf); + if (*rcnt >= '0' && *rcnt <= '9' && !strncmp ("RECENT", imap_next_word (rcnt), 6)) + recent = atoi (rcnt); + } else if (strstr (respbuf, "EXPUNGE")) { + char *id_str; + int id; + + d(fprintf (stderr, "*** We may have found an 'EXPUNGE' flag: %s\n", respbuf)); + /* Make sure it's in the form: "* %d EXPUNGE" */ + id_str = imap_next_word (respbuf); + if (*id_str >= '0' && *id_str <= '9' && !strncmp ("EXPUNGE", imap_next_word (id_str), 7)) { + id = atoi (id_str); + g_ptr_array_add (expunged, g_strdup_printf ("%d", id)); + } + } + } + } + + if (status == CAMEL_IMAP_OK) { + gchar *p; + + /* populate the return buffer with the server response */ + *ret = g_new (char, len + 1); + p = *ret; + + for (i = 0; i < data->len; i++) { + char *datap; + + datap = (char *) data->pdata[i]; + if (*datap == '.') + datap++; + len = strlen (datap); + memcpy (p, datap, len); + p += len; + *p++ = '\n'; + } + + *p = '\0'; + } else { + /* command failed */ + if (respbuf) { + char *word; + + word = imap_next_word (respbuf); /* should now point to status */ + + word = imap_next_word (word); /* points to fail message, if there is one */ + + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: %s", word); + } else { + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: Unknown"); + } + + *ret = NULL; + } + + /* Update the summary */ + if (folder && (recent > 0 || expunged->len > 0)) + camel_imap_folder_changed (folder, recent, expunged, ex); + + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + for (i = 0; i < expunged->len; i++) + g_free (expunged->pdata[i]); + g_ptr_array_free (expunged, TRUE); + + return status; +} + +/** + * camel_imap_fetch_command: Send a FETCH request to an IMAP server and get + * a multi-line response. + * @store: the IMAP store + * @folder: The folder to perform the operation in + * @ret: a pointer to return the full server response in + * @fmt: a printf-style format string, followed by arguments + * + * This camel method sends the IMAP FETCH command specified by @fmt and the + * following arguments to the IMAP store specified by @store. If the + * store is in a disconnected state, camel_imap_fetch_command will first + * re-connect the store before sending the specified IMAP command. It then + * reads the server's response and parses out the status code. If the caller + * passed a non-NULL pointer for @ret, camel_imap_fetch_command will set + * it to point to a buffer containing the rest of the response from the IMAP + * server. (If @ret was passed but there was no extended response, @ret will + * be set to NULL.) The caller function is responsible for freeing @ret. + * + * Return value: one of CAMEL_IMAP_OK (command executed successfully), + * CAMEL_IMAP_NO (operational error message), CAMEL_IMAP_BAD (error + * message from the server), or CAMEL_IMAP_FAIL (a protocol-level error + * occurred, and Camel is uncertain of the result of the command.) + **/ + +gint +camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...) +{ + /* Security Note/FIXME: We have to be careful about assuming + * that a server response is valid as the command we are + * calling may require a literal string response which could + * possibly contain strings that appear to be valid server + * responses but aren't. We should, therefor, find a way to + * determine whether we are actually reading server responses. + */ + gint status = CAMEL_IMAP_OK; + GPtrArray *data, *expunged; + gchar *respbuf, *cmdid; + guint32 len = 0; + gint recent = 0; + va_list ap; + gint i; + + status = check_current_folder (store, folder, fmt, ex); + if (status != CAMEL_IMAP_OK) + return status; + + /* send the command */ + va_start (ap, fmt); + if (!send_command (store, &cmdid, fmt, ap, ex)) { + va_end (ap); + return CAMEL_IMAP_FAIL; + } + va_end (ap); + + data = g_ptr_array_new (); + expunged = g_ptr_array_new (); + + /* read multi-line response */ + while (1) { + if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) { + /* cleanup */ + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + for (i = 0; i < expunged->len; i++) + g_free (expunged->pdata[i]); + g_ptr_array_free (expunged, TRUE); + + return CAMEL_IMAP_FAIL; + } + + g_ptr_array_add (data, respbuf); + len += strlen (respbuf) + 1; + + /* IMAPs multi-line response ends with the cmdid string at the beginning of the line */ + if (!strncmp (respbuf, cmdid, strlen (cmdid))) { + status = camel_imap_status (cmdid, respbuf); + break; + } + + /* If recent or expunge flags were somehow set and this + response doesn't begin with a '*' then + recent/expunged must have been misdetected */ + if ((recent || expunged->len > 0) && *respbuf != '*') { + d(fprintf (stderr, "hmmm, someone tried to pull a fast one on us.\n")); + + recent = 0; + + for (i = 0; i < expunged->len; i++) { + g_free (expunged->pdata[i]); + g_ptr_array_remove_index (expunged, i); + } + } + + /* Check for a RECENT in the untagged response */ + if (*respbuf == '*') { + if (strstr (respbuf, "RECENT")) { + char *rcnt; + + d(fprintf (stderr, "*** We may have found a 'RECENT' flag: %s\n", respbuf)); + /* Make sure it's in the form: "* %d RECENT" */ + rcnt = imap_next_word (respbuf); + if (*rcnt >= '0' && *rcnt <= '9' && !strncmp ("RECENT", imap_next_word (rcnt), 6)) + recent = atoi (rcnt); + } else if (strstr (respbuf, "EXPUNGE")) { + char *id_str; + int id; + + d(fprintf (stderr, "*** We may have found an 'EXPUNGE' flag: %s\n", respbuf)); + /* Make sure it's in the form: "* %d EXPUNGE" */ + id_str = imap_next_word (respbuf); + if (*id_str >= '0' && *id_str <= '9' && !strncmp ("EXPUNGE", imap_next_word (id_str), 7)) { + id = atoi (id_str); + g_ptr_array_add (expunged, g_strdup_printf ("%d", id)); + } + } + } + } + + if (status == CAMEL_IMAP_OK) { + gchar *p; + + /* populate the return buffer with the server response */ + *ret = g_new (char, len + 1); + p = *ret; + + for (i = 0; i < data->len; i++) { + char *datap; + + datap = (char *) data->pdata[i]; + if (*datap == '.') + datap++; + len = strlen (datap); + memcpy (p, datap, len); + p += len; + *p++ = '\n'; + } + + *p = '\0'; + } else { + /* command failed */ + if (respbuf) { + char *word; + + word = imap_next_word (respbuf); /* should now point to status */ + + word = imap_next_word (word); /* points to fail message, if there is one */ + + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: %s", word); + } else { + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: Unknown"); + } + + *ret = NULL; + } + + /* Update the summary */ + if (folder && (recent > 0 || expunged->len > 0)) + camel_imap_folder_changed (folder, recent, expunged, ex); + + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + for (i = 0; i < expunged->len; i++) + g_free (expunged->pdata[i]); + g_ptr_array_free (expunged, TRUE); + + return status; } /** @@ -915,13 +1063,86 @@ camel_imap_command_preliminary (CamelImapStore *store, char **cmdid, CamelExcept gint camel_imap_command_continuation (CamelImapStore *store, char **ret, char *cmdid, char *cmdbuf, CamelException *ex) { + gint status = CAMEL_IMAP_OK; + GPtrArray *data; + gchar *respbuf; + guint32 len = 0; + gint i; + if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex, "%s\r\n", cmdbuf) < 0) { if (ret) *ret = NULL; return CAMEL_IMAP_FAIL; } - return slurp_response (store, NULL, cmdid, ret, TRUE, ex); + data = g_ptr_array_new (); + + /* read multi-line response */ + while (1) { + if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) { + /* cleanup */ + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + return CAMEL_IMAP_FAIL; + } + + g_ptr_array_add (data, respbuf); + len += strlen (respbuf) + 1; + + /* IMAPs multi-line response ends with the cmdid string at the beginning of the line */ + if (!strncmp (respbuf, cmdid, strlen (cmdid))) { + status = camel_imap_status (cmdid, respbuf); + break; + } + } + + if (status == CAMEL_IMAP_OK) { + gchar *p; + + /* populate the return buffer with the server response */ + *ret = g_new (char, len + 1); + p = *ret; + + for (i = 0; i < data->len; i++) { + char *datap; + + datap = (char *) data->pdata[i]; + if (*datap == '.') + datap++; + len = strlen (datap); + memcpy (p, datap, len); + p += len; + *p++ = '\n'; + } + + *p = '\0'; + } else { + /* command failed */ + if (respbuf) { + char *word; + + word = imap_next_word (respbuf); /* should now point to status */ + + word = imap_next_word (word); /* points to fail message, if there is one */ + + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: %s", word); + } else { + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: Unknown"); + } + + *ret = NULL; + } + + /* cleanup */ + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + return status; } /** @@ -949,11 +1170,85 @@ gint camel_imap_command_continuation_with_stream (CamelImapStore *store, char **ret, char *cmdid, CamelStream *cstream, CamelException *ex) { + gint status = CAMEL_IMAP_OK; + GPtrArray *data; + gchar *respbuf; + guint32 len = 0; + gint i; + + /* send stream */ if (camel_remote_store_send_stream (CAMEL_REMOTE_STORE (store), cstream, ex) < 0) { if (ret) *ret = NULL; return CAMEL_IMAP_FAIL; } - return slurp_response (store, NULL, cmdid, ret, TRUE, ex); + data = g_ptr_array_new (); + + /* read the servers multi-line response */ + while (1) { + if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) { + /* cleanup */ + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + return CAMEL_IMAP_FAIL; + } + + g_ptr_array_add (data, respbuf); + len += strlen (respbuf) + 1; + + /* IMAPs multi-line response ends with the cmdid string at the beginning of the line */ + if (!strncmp (respbuf, cmdid, strlen (cmdid))) { + status = camel_imap_status (cmdid, respbuf); + break; + } + } + + if (status == CAMEL_IMAP_OK) { + gchar *p; + + /* populate the return buffer with the server response */ + *ret = g_new (char, len + 1); + p = *ret; + + for (i = 0; i < data->len; i++) { + char *datap; + + datap = (char *) data->pdata[i]; + if (*datap == '.') + datap++; + len = strlen (datap); + memcpy (p, datap, len); + p += len; + *p++ = '\n'; + } + + *p = '\0'; + } else { + /* command failed */ + if (respbuf) { + char *word; + + word = imap_next_word (respbuf); /* should now point to status */ + + word = imap_next_word (word); /* points to fail message, if there is one */ + + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: %s", word); + } else { + camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE, + "IMAP command failed: Unknown"); + } + + *ret = NULL; + } + + /* cleanup */ + for (i = 0; i < data->len; i++) + g_free (data->pdata[i]); + g_ptr_array_free (data, TRUE); + + return status; } diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h index eecc42a1e0..7aa911f394 100644 --- a/camel/providers/imap/camel-imap-store.h +++ b/camel/providers/imap/camel-imap-store.h @@ -89,6 +89,9 @@ gint camel_imap_command (CamelImapStore *store, CamelFolder *folder, gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...); +gint camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, + char **ret, CamelException *ex, char *fmt, ...); + /* multi-transactional commands... */ gint camel_imap_command_preliminary (CamelImapStore *store, char **cmdid, diff --git a/camel/providers/imap/camel-imap-stream.c b/camel/providers/imap/camel-imap-stream.c index f27e782c0a..a59be149d9 100644 --- a/camel/providers/imap/camel-imap-stream.c +++ b/camel/providers/imap/camel-imap-stream.c @@ -123,10 +123,10 @@ stream_read (CamelStream *stream, char *buffer, size_t n) gint status, part_len; camel_exception_init (&ex); - status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), - CAMEL_FOLDER (imap_stream->folder), - &result, &ex, "%s\r\n", - imap_stream->command); + status = camel_imap_fetch_command (CAMEL_IMAP_STORE (folder->parent_store), + CAMEL_FOLDER (imap_stream->folder), + &result, &ex, "%s\r\n", + imap_stream->command); /* FIXME: exception is ignored */ camel_exception_clear (&ex);