aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog18
-rw-r--r--camel/camel-remote-store.c2
-rw-r--r--camel/providers/imap/camel-imap-folder.c18
-rw-r--r--camel/providers/imap/camel-imap-store.c537
-rw-r--r--camel/providers/imap/camel-imap-store.h3
-rw-r--r--camel/providers/imap/camel-imap-stream.c8
6 files changed, 452 insertions, 134 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 <fejj@helixcode.com>
+
+ * 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 <peterw@helixcode.com>
* 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 <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));
+ /*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 <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));
+ /*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,25 +569,142 @@ 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)
+
+/**
+ * camel_imap_command: Send a command to a IMAP server.
+ * @store: the IMAP store
+ * @folder: The folder to perform the operation in
+ * @ret: a pointer to return the full server response in
+ * @ex: a CamelException.
+ * @fmt: a printf-style format string, followed by arguments
+ *
+ * This camel method sends the command specified by @fmt and the following
+ * arguments to the connected IMAP store specified by @store. 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_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_command (CamelImapStore *store, CamelFolder *folder, CamelException *ex, char *fmt, ...)
+{
+ char *cmdid, *respbuf, *word;
+ gint status = CAMEL_IMAP_OK;
+ va_list ap;
+
+ /* check for current folder */
+ 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);
+ g_free (cmdid);
+ return CAMEL_IMAP_FAIL;
+ }
+ va_end (ap);
+
+ /* read single line response */
+ if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) {
+ g_free (cmdid);
+ return CAMEL_IMAP_FAIL;
+ }
+
+ status = camel_imap_status (cmdid, respbuf);
+ g_free (cmdid);
+
+ if (status == CAMEL_IMAP_OK)
+ return status;
+
+ if (respbuf) {
+ /* get error response and set exception accordingly */
+ word = imap_next_word (respbuf); /* points 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: %s", "Unknown");
+ }
+
+ return status;
+}
+
+/**
+ * camel_imap_command_extended: Send a command to a 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 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_command_extended 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_command_extended 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.
+ *
+ * This camel method gets the additional data returned by "multi-line" IMAP
+ * 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.
+ *
+ * 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_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...)
{
gint status = CAMEL_IMAP_OK;
GPtrArray *data, *expunged;
- gchar *respbuf;
+ 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;
@@ -596,31 +713,12 @@ slurp_response (CamelImapStore *store, CamelFolder *folder, char *cmdid, char **
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;
- }
-
+ /* 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")) {
@@ -646,16 +744,10 @@ slurp_response (CamelImapStore *store, CamelFolder *folder, char *cmdid, char **
}
}
- /* 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) {
+ if (status == CAMEL_IMAP_OK) {
gchar *p;
- /* Command succeeded! Put the output into one big
- * string of love. */
-
+ /* populate the return buffer with the server response */
*ret = g_new (char, len + 1);
p = *ret;
@@ -673,7 +765,7 @@ slurp_response (CamelImapStore *store, CamelFolder *folder, char *cmdid, char **
*p = '\0';
} else {
- /* Bummer. Try to grab what the server said. */
+ /* command failed */
if (respbuf) {
char *word;
@@ -683,13 +775,17 @@ slurp_response (CamelImapStore *store, CamelFolder *folder, char *cmdid, char **
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;
}
- /* Can this be put into the 'if succeeded' bit?
- * Or can a failed command generate untagged responses? */
+ /* 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]);
@@ -702,37 +798,48 @@ slurp_response (CamelImapStore *store, CamelFolder *folder, char *cmdid, char **
return status;
}
-
/**
- * camel_imap_command: Send a command to a IMAP server.
+ * 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
- * @ex: a CamelException.
* @fmt: a printf-style format string, followed by arguments
*
- * This camel method sends the command specified by @fmt and the following
- * arguments to the connected IMAP store specified by @store. 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_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.
+ * 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_command (CamelImapStore *store, CamelFolder *folder, CamelException *ex, char *fmt, ...)
+camel_imap_fetch_command (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...)
{
- char *cmdid, *respbuf, *word;
+ /* 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;
- /* check for current folder */
status = check_current_folder (store, folder, fmt, ex);
if (status != CAMEL_IMAP_OK)
return status;
@@ -741,87 +848,128 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder, CamelException *
va_start (ap, fmt);
if (!send_command (store, &cmdid, fmt, ap, ex)) {
va_end (ap);
- g_free (cmdid);
return CAMEL_IMAP_FAIL;
}
va_end (ap);
- /* read single line response */
- if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0) {
- g_free (cmdid);
- return CAMEL_IMAP_FAIL;
- }
-
- status = camel_imap_status (cmdid, respbuf);
- g_free (cmdid);
+ data = g_ptr_array_new ();
+ expunged = g_ptr_array_new ();
- if (status == CAMEL_IMAP_OK)
- return status;
+ /* 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 (respbuf) {
- /* get error response and set exception accordingly */
- word = imap_next_word (respbuf); /* points to status */
- word = imap_next_word (word); /* points to fail message, if there is one */
+ if (status == CAMEL_IMAP_OK) {
+ gchar *p;
- camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- "IMAP command failed: %s", word);
+ /* 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 {
- camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- "IMAP command failed: %s", "Unknown");
+ /* 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;
}
- return status;
-}
-
-/**
- * camel_imap_command_extended: Send a command to a 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 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_command_extended 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_command_extended 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.
- *
- * This camel method gets the additional data returned by "multi-line" IMAP
- * commands, such as SELECT, LIST, FETCH, and various other commands.
- * The returned data is un-byte-stuffed, and has lines termined by
- * newlines rather than CR/LF pairs.
- *
- * 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_command_extended (CamelImapStore *store, CamelFolder *folder, char **ret, CamelException *ex, char *fmt, ...)
-{
- gint status = CAMEL_IMAP_OK;
- gchar *cmdid;
- va_list ap;
+ /* Update the summary */
+ if (folder && (recent > 0 || expunged->len > 0))
+ camel_imap_folder_changed (folder, recent, expunged, ex);
- status = check_current_folder (store, folder, fmt, ex);
- if (status != CAMEL_IMAP_OK)
- return status;
+ for (i = 0; i < data->len; i++)
+ g_free (data->pdata[i]);
+ g_ptr_array_free (data, TRUE);
- /* 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);
+ for (i = 0; i < expunged->len; i++)
+ g_free (expunged->pdata[i]);
+ g_ptr_array_free (expunged, TRUE);
- return slurp_response (store, folder, cmdid, ret, FALSE, ex);
+ 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);