aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog22
-rw-r--r--camel/providers/imap/Makefile.am4
-rw-r--r--camel/providers/imap/camel-imap-command.c391
-rw-r--r--camel/providers/imap/camel-imap-command.h58
-rw-r--r--camel/providers/imap/camel-imap-folder.c372
-rw-r--r--camel/providers/imap/camel-imap-store.c962
-rw-r--r--camel/providers/imap/camel-imap-store.h44
-rw-r--r--camel/providers/imap/camel-imap-utils.c74
-rw-r--r--camel/providers/imap/camel-imap-utils.h2
9 files changed, 735 insertions, 1194 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index 924c5681f1..9dc9eb00cc 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,25 @@
+2000-10-03 Dan Winship <danw@helixcode.com>
+
+ * providers/imap/camel-imap-command.c: New file containing
+ camel_imap_command and friends. Major camel_imap_command rewrite
+ to remove duplicated code, make the parsing of literals be
+ more safe/correct, deal with RECENT/EXPUNGE responses more
+ consistently, and make it possible to implement the AUTHENTICATE
+ command.
+
+ * providers/imap/camel-imap-utils.c (imap_parse_nstring): New
+ function, to parse an IMAP "nstring".
+
+ * providers/imap/camel-imap-store.c: Move command stuff to
+ camel-imap-command.c. Update for camel_imap_command changes.
+
+ * providers/imap/camel-imap-folder.c: Update for
+ camel_imap_command changes.
+ (imap_append_message): CRLF filter the message before sending it.
+
+ * providers/imap/Makefile.am: Add camel-imap-command.[ch], remove
+ camel-imap-stream.[ch] for now.
+
2000-10-02 Jeffrey Stedfast <fejj@helixcode.com>
* camel-mime-message.c (camel_mime_message_has_8bit_parts): New
diff --git a/camel/providers/imap/Makefile.am b/camel/providers/imap/Makefile.am
index 5ff249739f..15e1b850e8 100644
--- a/camel/providers/imap/Makefile.am
+++ b/camel/providers/imap/Makefile.am
@@ -20,16 +20,16 @@ INCLUDES = -I.. \
-DG_LOG_DOMAIN=\"camel-imap-provider\"
libcamelimap_la_SOURCES = \
+ camel-imap-command.c \
camel-imap-folder.c \
camel-imap-provider.c \
camel-imap-store.c \
- camel-imap-stream.c \
camel-imap-utils.c
libcamelimapinclude_HEADERS = \
+ camel-imap-command.h \
camel-imap-folder.h \
camel-imap-store.h \
- camel-imap-stream.h \
camel-imap-utils.h
libcamelimap_la_LDFLAGS = -version-info 0:0:0
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
new file mode 100644
index 0000000000..e06de34db4
--- /dev/null
+++ b/camel/providers/imap/camel-imap-command.c
@@ -0,0 +1,391 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-command.c: IMAP command sending/parsing routines */
+
+/*
+ * Authors:
+ * Dan Winship <danw@helixcode.com>
+ * Jeffrey Stedfast <fejj@helixcode.com>
+ *
+ * Copyright 2000 Helix Code, Inc. (www.helixcode.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Street #330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+
+#include <config.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "camel-imap-command.h"
+#include "camel-imap-utils.h"
+#include "camel-imap-folder.h"
+#include <camel/camel-exception.h>
+
+static char *imap_read_untagged (CamelImapStore *store, char *line,
+ CamelException *ex);
+static CamelImapResponse *imap_read_response (CamelImapStore *store,
+ CamelException *ex);
+
+/**
+ * camel_imap_command: Send a command to a IMAP server and get a response
+ * @store: the IMAP store
+ * @folder: The folder to perform the operation in (or %NULL if not
+ * relevant).
+ * @ex: a CamelException
+ * @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. It then
+ * reads the server's response(s) and parses the final result.
+ *
+ * Return value: %NULL if an error occurred (in which case @ex will
+ * be set). Otherwise, a CamelImapResponse describing the server's
+ * response, which the caller must free with camel_imap_response_free().
+ **/
+CamelImapResponse *
+camel_imap_command (CamelImapStore *store, CamelFolder *folder,
+ CamelException *ex, const char *fmt, ...)
+{
+ gchar *cmdbuf;
+ va_list ap;
+
+ /* Check for current folder */
+ if (folder && folder != store->current_folder) {
+ char *folder_path;
+ CamelImapResponse *response;
+
+ folder_path = camel_imap_store_folder_path (store,
+ folder->full_name);
+ response = camel_imap_command (store, NULL, ex,
+ "SELECT %s", folder_path);
+ g_free (folder_path);
+
+ if (!response) {
+ store->current_folder = NULL;
+ return NULL;
+ }
+ camel_imap_response_free (response);
+
+ store->current_folder = folder;
+ }
+
+ /* Send the command */
+ va_start (ap, fmt);
+ cmdbuf = g_strdup_vprintf (fmt, ap);
+ va_end (ap);
+
+ camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex,
+ "A%.5d %s\r\n", store->command++,
+ cmdbuf);
+ g_free (cmdbuf);
+ if (camel_exception_is_set (ex))
+ return NULL;
+
+ /* Read the response. */
+ return imap_read_response (store, ex);
+}
+
+/**
+ * camel_imap_command_continuation: Send more command data to the IMAP server
+ * @store: the IMAP store
+ * @ex: a CamelException
+ * @cmdbuf: buffer containing the response/request data
+ *
+ * This method is for sending continuing responses to the IMAP server
+ * after camel_imap_command returns a CAMEL_IMAP_PLUS response.
+ *
+ * Return value: as for camel_imap_command()
+ **/
+CamelImapResponse *
+camel_imap_command_continuation (CamelImapStore *store, CamelException *ex,
+ const char *cmdbuf)
+{
+ if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex,
+ "%s\r\n", cmdbuf) < 0)
+ return NULL;
+
+ return imap_read_response (store, ex);
+}
+
+/* Read the response to an IMAP command. */
+static CamelImapResponse *
+imap_read_response (CamelImapStore *store, CamelException *ex)
+{
+ CamelImapResponse *response;
+ int number, recent = 0;
+ GArray *expunged = NULL;
+ char *respbuf, *retcode, *p;
+
+ /* Read first line */
+ if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store),
+ &respbuf, ex) < 0)
+ return NULL;
+
+ response = g_new0 (CamelImapResponse, 1);
+ response->untagged = g_ptr_array_new ();
+
+ /* Check for untagged data */
+ while (!strncmp (respbuf, "* ", 2)) {
+ /* Read the rest of the response if it is multi-line. */
+ respbuf = imap_read_untagged (store, respbuf, ex);
+ if (camel_exception_is_set (ex))
+ break;
+
+ /* If it starts with a number, we might deal with
+ * it ourselves.
+ */
+ number = strtoul (respbuf + 2, &p, 10);
+ if (p != respbuf + 2) {
+ p = imap_next_word (p);
+ if (!g_strcasecmp (p, "RECENT")) {
+ recent = number;
+ g_free (respbuf);
+ goto next;
+ } else if (!g_strcasecmp (p, "EXPUNGE")) {
+ if (!expunged) {
+ expunged = g_array_new (FALSE, FALSE,
+ sizeof (int));
+ }
+ g_array_append_val (expunged, number);
+ g_free (respbuf);
+ goto next;
+ }
+ }
+
+ g_ptr_array_add (response->untagged, respbuf);
+ next:
+ if (camel_remote_store_recv_line (
+ CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0)
+ break;
+ }
+
+ /* Update the summary */
+ if (store->current_folder && (recent > 0 || expunged)) {
+ camel_imap_folder_changed (store->current_folder, recent,
+ expunged, NULL);
+ }
+ if (expunged)
+ g_array_free (expunged, TRUE);
+
+ if (camel_exception_is_set (ex)) {
+ camel_imap_response_free (response);
+ return NULL;
+ }
+
+ response->status = respbuf;
+
+ /* Check for OK or continuation response. */
+ if (!strncmp (respbuf, "+ ", 2))
+ return response;
+ retcode = imap_next_word (respbuf);
+ if (!strncmp (retcode, "OK", 2))
+ return response;
+
+ /* We should never get BAD, or anything else but +, OK, or NO
+ * for that matter.
+ */
+ if (strncmp (retcode, "NO", 2) != 0) {
+ g_warning ("Unexpected response from IMAP server: %s",
+ respbuf);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ "Unexpected response from IMAP server: "
+ "%s", respbuf);
+ camel_imap_response_free (response);
+ return NULL;
+ }
+
+ retcode = imap_next_word (retcode);
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ "IMAP command failed: %s",
+ retcode ? retcode : "Unknown error");
+ camel_imap_response_free (response);
+ return NULL;
+}
+
+/* Given a line that is the start of an untagged response, read and
+ * return the complete response. (This will be a no-op if the line
+ * in question doesn't end with a literal.)
+ *
+ * FIXME: this won't deal with multiple literals in a single response.
+ */
+static char *
+imap_read_untagged (CamelImapStore *store, char *line, CamelException *ex)
+{
+ int fulllen, length, left, i;
+ GPtrArray *data;
+ char *end, *p;
+
+ p = strrchr (line, '{');
+ if (!p)
+ return line;
+
+ length = strtoul (p + 1, &end, 10);
+ if (*end != '}' || *(end + 1) || end == p + 1)
+ return line;
+
+ fulllen = length + strlen (line) + 1;
+
+ /* OK. We have a literal. @length is the length including CRLF
+ * pairs, which camel_remote_store_recv_line won't return.
+ */
+ data = g_ptr_array_new ();
+ g_ptr_array_add (data, line);
+ left = length;
+ while (1) {
+ if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store),
+ &line, ex) < 0) {
+ for (i = 0; i < data->len; i++)
+ g_free (data->pdata[i]);
+ g_ptr_array_free (data, TRUE);
+ return NULL;
+ }
+ g_ptr_array_add (data, line);
+
+ if (left <= 0)
+ break;
+
+ left -= strlen (line) + 2;
+
+ /* The output string will have only LF, not CRLF, so
+ * decrement the length by one.
+ */
+ length--;
+ }
+
+ /* p points to the "{" in the line that starts the literal.
+ * The length of the CR-less response must be less than or
+ * equal to the length of the response with CRs, therefore
+ * overwriting the old value with the new value cannot cause
+ * an overrun.
+ */
+ sprintf (p, "{%d}", length);
+
+ /* Now reassemble the data. */
+ p = line = g_malloc (fulllen + 1);
+ for (i = 0; i < data->len; i++) {
+ length = strlen (data->pdata[i]);
+ memcpy (p, data->pdata[i], length);
+ g_free (data->pdata[i]);
+ p += length;
+ *p++ = '\n';
+ }
+ *p = '\0';
+ g_ptr_array_free (data, TRUE);
+ return line;
+}
+
+
+/**
+ * camel_imap_response_free:
+ * response: a CamelImapResponse:
+ *
+ * Frees all of the data in @response.
+ **/
+void
+camel_imap_response_free (CamelImapResponse *response)
+{
+ int i;
+
+ if (!response)
+ return;
+ for (i = 0; i < response->untagged->len; i++)
+ g_free (response->untagged->pdata[i]);
+ g_ptr_array_free (response->untagged, TRUE);
+ g_free (response->status);
+ g_free (response);
+}
+
+/**
+ * camel_imap_response_extract:
+ * @response: the response data returned from camel_imap_command
+ * @type: the response type to extract
+ * @ex: a CamelException
+ *
+ * This checks that @response contains a single untagged response of
+ * type @type and returns just that response data. If @response
+ * doesn't contain the right information, the function will set @ex and
+ * return %NULL. Either way, @response will be freed.
+ *
+ * Return value: the desired response string, which the caller must free.
+ **/
+char *
+camel_imap_response_extract (CamelImapResponse *response, const char *type,
+ CamelException *ex)
+{
+ int len = strlen (type), i;
+ char *resp;
+
+ for (i = 0; i < response->untagged->len; i++) {
+ resp = response->untagged->pdata[i];
+ /* Skip "* ", and initial sequence number, if present */
+ strtoul (resp + 2, &resp, 10);
+ if (*resp == ' ')
+ resp++;
+
+ if (!g_strncasecmp (resp, type, len))
+ break;
+ g_free (resp);
+ }
+
+ if (i < response->untagged->len) {
+ resp = response->untagged->pdata[i];
+ for (i++; i < response->untagged->len; i++)
+ g_free (response->untagged->pdata[i]);
+ } else {
+ resp = NULL;
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ "IMAP server response did not contain "
+ "%s information", type);
+ }
+
+ g_ptr_array_free (response->untagged, TRUE);
+ g_free (response->status);
+ g_free (response);
+ return resp;
+}
+
+/**
+ * camel_imap_response_extract_continuation:
+ * @response: the response data returned from camel_imap_command
+ * @ex: a CamelException
+ *
+ * This checks that @response contains a continuation response, and
+ * returns just that data. If @response doesn't contain a continuation
+ * response, the function will set @ex and return %NULL. Either way,
+ * @response will be freed.
+ *
+ * Return value: the desired response string, which the caller must free.
+ **/
+char *
+camel_imap_response_extract_continuation (CamelImapResponse *response,
+ CamelException *ex)
+{
+ char *status;
+
+ if (response->status && !strncmp (response->status, "+ ", 2)) {
+ status = response->status;
+ response->status = NULL;
+ camel_imap_response_free (response);
+ return status;
+ }
+
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ "Unexpected OK response from IMAP server: %s",
+ response->status);
+ camel_imap_response_free (response);
+ return NULL;
+}
diff --git a/camel/providers/imap/camel-imap-command.h b/camel/providers/imap/camel-imap-command.h
new file mode 100644
index 0000000000..38e290c379
--- /dev/null
+++ b/camel/providers/imap/camel-imap-command.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/* camel-imap-command.h: IMAP command sending/parsing routines */
+
+/*
+ * Authors:
+ * Dan Winship <danw@helixcode.com>
+ * Jeffrey Stedfast <fejj@helixcode.com>
+ *
+ * Copyright (C) 2000 Helix Code, Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
+ * USA
+ */
+
+
+#ifndef CAMEL_IMAP_COMMAND_H
+#define CAMEL_IMAP_COMMAND_H 1
+
+#ifdef __cplusplus
+extern "C" {
+#pragma }
+#endif /* __cplusplus }*/
+
+#include "camel-imap-store.h"
+
+typedef struct {
+ GPtrArray *untagged;
+ char *status;
+} CamelImapResponse;
+
+CamelImapResponse *camel_imap_command (CamelImapStore *store,
+ CamelFolder *folder,
+ CamelException *ex,
+ const char *fmt, ...);
+CamelImapResponse *camel_imap_command_continuation (CamelImapStore *store,
+ CamelException *ex,
+ const char *cmdbuf);
+
+void camel_imap_response_free (CamelImapResponse *response);
+char *camel_imap_response_extract (CamelImapResponse *response,
+ const char *type,
+ CamelException *ex);
+char *camel_imap_response_extract_continuation (CamelImapResponse *response,
+ CamelException *ex);
+
+#endif /* CAMEL_IMAP_COMMAND_H */
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index ab2d7f88b9..21f4d3bfc2 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -37,6 +37,7 @@
#include <gal/util/e-util.h>
#include "camel-imap-folder.h"
+#include "camel-imap-command.h"
#include "camel-imap-store.h"
#include "camel-imap-stream.h"
#include "camel-imap-utils.h"
@@ -236,6 +237,7 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelImapResponse *response;
gint i, max;
if (expunge) {
@@ -249,20 +251,20 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
for (i = 0; i < max; i++) {
CamelMessageInfo *info;
- info = (CamelMessageInfo *) g_ptr_array_index (imap_folder->summary, i);
+ info = g_ptr_array_index (imap_folder->summary, i);
if (info->flags & CAMEL_MESSAGE_FOLDER_FLAGGED) {
char *flags;
flags = imap_create_flag_list (info->flags);
if (flags) {
- gint s;
-
- s = camel_imap_command_extended (store, folder, NULL, ex,
- "UID STORE %s FLAGS.SILENT %s",
- info->uid, flags);
- if (s != CAMEL_IMAP_OK)
- return;
+ response = camel_imap_command (
+ store, folder, ex,
+ "UID STORE %s FLAGS.SILENT %s",
+ info->uid, flags);
g_free (flags);
+ if (!response)
+ return;
+ camel_imap_response_free (response);
}
info->flags &= ~CAMEL_MESSAGE_FOLDER_FLAGGED;
}
@@ -273,30 +275,32 @@ imap_sync (CamelFolder *folder, gboolean expunge, CamelException *ex)
static void
imap_expunge (CamelFolder *folder, CamelException *ex)
{
+ CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
+
imap_sync (folder, FALSE, ex);
- camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder, NULL, ex, "EXPUNGE");
+ response = camel_imap_command (store, folder, ex, "EXPUNGE");
+ camel_imap_response_free (response);
}
static gint
imap_get_message_count_internal (CamelFolder *folder, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
- gchar *result, *msg_count, *folder_path;
- GPtrArray *response;
- gint status, count = 0;
+ char *result, *msg_count, *folder_path;
+ CamelImapResponse *response;
+ int count = 0;
folder_path = camel_imap_store_folder_path (store, folder->full_name);
-
if (store->has_status_capability)
- status = camel_imap_command_extended (store, folder, &response, ex,
- "STATUS \"%s\" (MESSAGES)", folder_path);
+ response = camel_imap_command (store, folder, ex,
+ "STATUS \"%s\" (MESSAGES)",
+ folder_path);
else
- status = camel_imap_command_extended (store, folder, &response, ex,
- "EXAMINE \"%s\"", folder_path);
-
+ response = camel_imap_command (store, folder, ex,
+ "EXAMINE \"%s\"", folder_path);
g_free (folder_path);
-
- if (status != CAMEL_IMAP_OK)
+ if (!response)
return 0;
/* parse out the message count */
@@ -368,14 +372,16 @@ imap_get_unread_message_count (CamelFolder *folder)
}
static void
-imap_append_message (CamelFolder *folder, CamelMimeMessage *message, const CamelMessageInfo *info, CamelException *ex)
+imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
+ const CamelMessageInfo *info, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
CamelStream *memstream;
+ CamelMimeFilter *crlf_filter;
+ CamelStreamFilter *streamfilter;
GByteArray *ba;
- gchar *cmdid;
- gchar *folder_path, *flagstr;
- gint status;
+ char *folder_path, *flagstr, *result;
folder_path = camel_imap_store_folder_path (store, folder->full_name);
@@ -384,74 +390,83 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message, const Camel
flagstr = imap_create_flag_list (info->flags);
else
flagstr = NULL;
-
+
+ /* FIXME: We could avoid this if we knew how big the message was. */
+ memstream = camel_stream_mem_new ();
ba = g_byte_array_new ();
- memstream = camel_stream_mem_new_with_byte_array (ba);
- /* FIXME: we need to crlf/dot filter */
- camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message), memstream);
- camel_stream_write_string (memstream, "\r\n");
- camel_stream_reset (memstream);
-
- status = camel_imap_command_preliminary (store, &cmdid, ex, "APPEND %s%s%s {%d}",
- folder_path, flagstr ? " " : "",
- flagstr ? flagstr : "", ba->len - 2);
+ camel_stream_mem_set_byte_array (CAMEL_STREAM_MEM (memstream), ba);
+
+ streamfilter = camel_stream_filter_new_with_stream (memstream);
+ crlf_filter = camel_mime_filter_crlf_new (
+ CAMEL_MIME_FILTER_CRLF_ENCODE,
+ CAMEL_MIME_FILTER_CRLF_MODE_CRLF_ONLY);
+ camel_stream_filter_add (streamfilter, crlf_filter);
+ camel_data_wrapper_write_to_stream (CAMEL_DATA_WRAPPER (message),
+ CAMEL_STREAM (streamfilter));
+ camel_object_unref (CAMEL_OBJECT (streamfilter));
+ camel_object_unref (CAMEL_OBJECT (crlf_filter));
+ camel_object_unref (CAMEL_OBJECT (memstream));
+
+ response = camel_imap_command (store, NULL, ex, "APPEND %s%s%s {%d}",
+ folder_path, flagstr ? " " : "",
+ flagstr ? flagstr : "", ba->len);
g_free (folder_path);
g_free (flagstr);
- if (status != CAMEL_IMAP_PLUS) {
- g_free (cmdid);
- camel_object_unref (CAMEL_OBJECT (memstream));
+ if (!response) {
+ g_byte_array_free (ba, TRUE);
return;
}
-
+ result = camel_imap_response_extract_continuation (response, ex);
+ if (!result) {
+ g_byte_array_free (ba, TRUE);
+ return;
+ }
+ g_free (result);
+
/* send the rest of our data - the mime message */
- status = camel_imap_command_continuation_with_stream (store, NULL, cmdid, memstream, ex);
- g_free (cmdid);
-
- if (status != CAMEL_IMAP_OK)
+ g_byte_array_append (ba, "\0", 3);
+ response = camel_imap_command_continuation (store, ex, ba->data);
+ g_byte_array_free (ba, TRUE);
+ if (!response)
return;
-
- camel_object_unref (CAMEL_OBJECT (memstream));
- camel_imap_folder_changed (folder, 1, NULL, ex);
+ camel_imap_response_free (response);
}
static void
-imap_copy_message_to (CamelFolder *source, const char *uid, CamelFolder *destination, CamelException *ex)
+imap_copy_message_to (CamelFolder *source, const char *uid,
+ CamelFolder *destination, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
+ CamelImapResponse *response;
char *folder_path;
- int status;
folder_path = camel_imap_store_folder_path (store, destination->full_name);
- status = camel_imap_command_extended (store, source, NULL, ex,
- "UID COPY %s %s", uid, folder_path);
+ response = camel_imap_command (store, source, ex, "UID COPY %s %s",
+ uid, folder_path);
+ camel_imap_response_free (response);
g_free (folder_path);
-
- if (status != CAMEL_IMAP_OK)
- return;
-
- camel_imap_folder_changed (destination, 1, NULL, ex);
}
/* FIXME: Duplication of code! */
static void
-imap_move_message_to (CamelFolder *source, const char *uid, CamelFolder *destination, CamelException *ex)
+imap_move_message_to (CamelFolder *source, const char *uid,
+ CamelFolder *destination, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
+ CamelImapResponse *response;
char *folder_path;
- int status;
-
+
folder_path = camel_imap_store_folder_path (store, destination->full_name);
- status = camel_imap_command_extended (store, source, NULL, ex,
- "UID COPY %s %s", uid, folder_path);
+ response = camel_imap_command (store, source, ex, "UID COPY %s %s",
+ uid, folder_path);
+ camel_imap_response_free (response);
g_free (folder_path);
-
- if (status != CAMEL_IMAP_OK)
+
+ if (camel_exception_is_set (ex))
return;
-
+
camel_folder_delete_message (source, uid);
-
- camel_imap_folder_changed (destination, 1, NULL, ex);
}
static GPtrArray *
@@ -480,142 +495,41 @@ static CamelMimeMessage *
imap_get_message (CamelFolder *folder, const gchar *uid, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
- CamelStream *msgstream = NULL;
- CamelMimeMessage *msg = NULL;
- gchar *result, *header, *body, *mesg, *p, *q, *data_item;
- int status, part_len;
-
- if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
- data_item = "BODY.PEEK[HEADER]";
- else
- data_item = "RFC822.HEADER";
-
- status = camel_imap_fetch_command (store, folder, &result, ex,
- "UID FETCH %s %s", uid, data_item);
-
- if (!result || status != CAMEL_IMAP_OK)
- return NULL;
-
- /* parse out the message part */
- for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
- switch (*p) {
- case '"':
- /* a quoted string - section 4.3 */
- p++;
- for (q = p; *q && *q != '"' && *q != '\n'; q++);
- part_len = (gint) (q - p);
-
- break;
- case '{':
- /* a literal string - section 4.3 */
- part_len = atoi (p + 1);
- for ( ; *p && *p != '\n'; p++);
- if (*p != '\n') {
- g_free (result);
- return NULL;
- }
-
- /* advance to the beginning of the actual data */
- p++;
-
- /* calculate the new part-length */
- for (q = p; *q && (q - p) <= part_len; q++) {
- if (*q == '\n')
- part_len--;
- }
-
- /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
- for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
- part_len++;
-
- break;
- default:
- /* Bad input */
- g_free (result);
+ CamelImapResponse *response;
+ CamelStream *msgstream;
+ CamelMimeMessage *msg;
+ char *result, *mesg, *p;
+ int len;
+
+ response = camel_imap_command (store, folder, ex,
+ "UID FETCH %s RFC822", uid);
+ if (!response)
return NULL;
- }
-
- header = g_strndup (p, part_len);
-
- g_free (result);
- d(fprintf (stderr, "*** We got the header ***\n"));
-
- if (store->server_level >= IMAP_LEVEL_IMAP4REV1)
- data_item = "BODY[TEXT]";
- else
- data_item = "RFC822.TEXT";
-
- status = camel_imap_fetch_command (store, folder, &result, ex,
- "UID FETCH %s %s", uid, data_item);
-
- if (!result || status != CAMEL_IMAP_OK) {
- g_free (header);
+ result = camel_imap_response_extract (response, "FETCH", ex);
+ if (!result)
return NULL;
+
+ p = strstr (result, "RFC822");
+ if (p) {
+ p += 7;
+ mesg = imap_parse_nstring (&p, &len);
}
-
- /* parse out the message part */
- for (p = result; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
- switch (*p) {
- case '"':
- /* a quoted string - section 4.3 */
- p++;
- for (q = p; *q && *q != '"' && *q != '\n'; q++);
- part_len = (gint) (q - p);
-
- break;
- case '{':
- /* a literal string - section 4.3 */
- part_len = atoi (p + 1);
- for ( ; *p && *p != '\n'; p++);
- if (*p != '\n') {
- g_free (result);
- g_free (header);
- return NULL;
- }
-
- /* advance to the beginning of the actual data */
- p++;
-
- /* calculate the new part-length */
- for (q = p; *q && (q - p) <= part_len; q++) {
- if (*q == '\n')
- part_len--;
- }
-
- /* FIXME: This is a hack for IMAP daemons that send us a UID at the end of each FETCH */
- for ( ; q > p && *(q-1) != '\n'; q--, part_len--);
- part_len++;
-
- break;
- default:
- /* Bad input */
+ if (!p) {
+ camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
+ "Could not find message body in FETCH "
+ "response.");
g_free (result);
- g_free (header);
return NULL;
}
-
- body = g_strndup (p, part_len);
-
g_free (result);
- d(fprintf (stderr, "*** We got the body ***\n"));
-
- mesg = g_strdup_printf ("%s\n%s", header, body);
- g_free (header);
- g_free (body);
- d(fprintf (stderr, "*** We got the mesg ***\n"));
-
- d(fprintf (stderr, "Message:\n%s\n", mesg));
-
- msgstream = camel_stream_mem_new_with_buffer (mesg, strlen (mesg) + 1);
+
+ msgstream = camel_stream_mem_new_with_buffer (mesg, len);
msg = camel_mime_message_new ();
- d(fprintf (stderr, "*** We created the camel_mime_message ***\n"));
-
- camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg), msgstream);
+ camel_data_wrapper_construct_from_stream (CAMEL_DATA_WRAPPER (msg),
+ msgstream);
camel_object_unref (CAMEL_OBJECT (msgstream));
-
- d(fprintf (stderr, "*** We're returning... ***\n"));
-
g_free (mesg);
+
return msg;
}
@@ -673,7 +587,8 @@ imap_protocol_get_summary_specifier (CamelImapStore *store)
sect_end = "";
}
- return g_strdup_printf ("UID FLAGS %s (%s)%s", sect_begin, headers_wanted, sect_end);
+ return g_strdup_printf ("UID FLAGS %s (%s)%s", sect_begin,
+ headers_wanted, sect_end);
}
static GPtrArray *
@@ -682,10 +597,11 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
/* This ALWAYS updates the summary except on fail */
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
CamelImapFolder *imap_folder = CAMEL_IMAP_FOLDER (folder);
+ CamelImapResponse *response;
GPtrArray *summary = NULL, *headers = NULL;
GHashTable *hash = NULL;
- gint num, i, j, status = 0;
- char *result, *q, *node;
+ int num, i, j;
+ char *q;
const char *received;
char *summary_specifier;
struct _header_raw *h = NULL, *tail = NULL;
@@ -706,17 +622,18 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
}
summary_specifier = imap_protocol_get_summary_specifier (store);
-
if (num == 1) {
- status = camel_imap_fetch_command (store, folder, &result, ex,
- "FETCH 1 (%s)", summary_specifier);
+ response = camel_imap_command (store, folder, ex,
+ "FETCH 1 (%s)",
+ summary_specifier);
} else {
- status = camel_imap_fetch_command (store, folder, &result, ex,
- "FETCH 1:%d (%s)", num, summary_specifier);
+ response = camel_imap_command (store, folder, ex,
+ "FETCH 1:%d (%s)", num,
+ summary_specifier);
}
g_free (summary_specifier);
- if (status != CAMEL_IMAP_OK) {
+ if (!response) {
if (!imap_folder->summary) {
imap_folder->summary = g_ptr_array_new ();
imap_folder->summary_hash = g_hash_table_new (g_str_hash, g_str_equal);
@@ -724,32 +641,12 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
return imap_folder->summary;
}
-
+ headers = response->untagged;
+
/* initialize our new summary-to-be */
summary = g_ptr_array_new ();
hash = g_hash_table_new (g_str_hash, g_str_equal);
- /* create our array of headers from the server response */
- headers = g_ptr_array_new ();
- node = result;
- for (i = 1; node; i++) {
- char *end;
-
- if ((end = strstr (node + 2, "\n*"))) {
- g_ptr_array_add (headers, g_strndup (node, (gint)(end - node)));
- } else {
- g_ptr_array_add (headers, g_strdup (node));
- }
- node = end;
- }
- if (i < num) {
- d(fprintf (stderr, "IMAP server didn't respond with as many headers as we expected...\n"));
- /* should we error?? */
- }
-
- g_free (result);
- result = NULL;
-
for (i = 0; i < headers->len; i++) {
CamelMessageInfo *info;
char *uid, *flags, *header;
@@ -834,10 +731,7 @@ imap_get_summary_internal (CamelFolder *folder, CamelException *ex)
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);
+ camel_imap_response_free (response);
/* clean up any previous summary data */
imap_folder_summary_free (imap_folder);
@@ -861,22 +755,24 @@ static CamelMessageInfo *
imap_get_message_info_internal (CamelFolder *folder, guint id, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (folder->parent_store);
+ CamelImapResponse *response;
CamelMessageInfo *info = NULL;
struct _header_raw *h, *tail = NULL;
const char *received;
char *result, *uid, *flags, *header, *q;
char *summary_specifier;
- int j, status;
+ int j;
/* we don't have a cached copy, so fetch it */
summary_specifier = imap_protocol_get_summary_specifier (store);
-
- status = camel_imap_fetch_command (store, folder, &result, ex,
- "FETCH %d (%s)", id, summary_specifier);
-
+ response = camel_imap_command (store, folder, ex,
+ "FETCH %d (%s)", id, summary_specifier);
g_free (summary_specifier);
-
- if (status != CAMEL_IMAP_OK)
+
+ if (!response)
+ return NULL;
+ result = camel_imap_response_extract (response, "FETCH", ex);
+ if (!result)
return NULL;
/* lets grab the UID... */
@@ -977,9 +873,9 @@ imap_get_message_info (CamelFolder *folder, const char *uid)
static GPtrArray *
imap_search_by_expression (CamelFolder *folder, const char *expression, CamelException *ex)
{
- GPtrArray *response, *uids = NULL;
+ CamelImapResponse *response;
+ GPtrArray *uids = NULL;
char *result, *sexp, *p;
- int status;
d(fprintf (stderr, "camel sexp: '%s'\n", expression));
sexp = imap_translate_sexp (expression);
@@ -992,12 +888,12 @@ imap_search_by_expression (CamelFolder *folder, const char *expression, CamelExc
return uids;
}
- status = camel_imap_command_extended (CAMEL_IMAP_STORE (folder->parent_store), folder,
- &response, NULL, "UID SEARCH %s", sexp);
+ response = camel_imap_command (CAMEL_IMAP_STORE (folder->parent_store),
+ folder, NULL, "UID SEARCH %s", sexp);
g_free (sexp);
-
- if (status != CAMEL_IMAP_OK)
+ if (!response)
return uids;
+
result = camel_imap_response_extract (response, "SEARCH", NULL);
if (!result)
return uids;
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index dcb3782e89..cb7df3d1cb 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -35,6 +35,7 @@
#include "camel-imap-store.h"
#include "camel-imap-folder.h"
#include "camel-imap-utils.h"
+#include "camel-imap-command.h"
#include "camel-folder.h"
#include "camel-exception.h"
#include "camel-session.h"
@@ -64,8 +65,6 @@ static CamelFolderInfo *get_folder_info (CamelStore *store, const char *top,
gboolean fast, gboolean recursive,
CamelException *ex);
static void imap_keepalive (CamelRemoteStore *store);
-/*static gboolean stream_is_alive (CamelStream *istream);*/
-static int camel_imap_status (char *cmdid, char *respbuf);
static void
camel_imap_store_class_init (CamelImapStoreClass *camel_imap_store_class)
@@ -189,9 +188,8 @@ imap_connect (CamelService *service, CamelException *ex)
CamelImapStore *store = CAMEL_IMAP_STORE (service);
CamelSession *session = camel_service_get_session (CAMEL_SERVICE (store));
gchar *result, *buf, *errbuf = NULL;
- GPtrArray *response;
+ CamelImapResponse *response;
gboolean authenticated = FALSE;
- gint status;
if (CAMEL_SERVICE_CLASS (remote_store_class)->connect (service, ex) == FALSE)
return FALSE;
@@ -237,11 +235,11 @@ imap_connect (CamelService *service, CamelException *ex)
}
}
- status = camel_imap_command (store, NULL, ex, "LOGIN \"%s\" \"%s\"",
- service->url->user,
- service->url->passwd);
-
- if (status != CAMEL_IMAP_OK) {
+ response = camel_imap_command (store, NULL, ex,
+ "LOGIN \"%s\" \"%s\"",
+ service->url->user,
+ service->url->passwd);
+ if (!response) {
errbuf = g_strdup_printf ("Unable to authenticate to IMAP server.\n"
"%s\n\n",
camel_exception_get_description (ex));
@@ -249,14 +247,14 @@ imap_connect (CamelService *service, CamelException *ex)
} else {
g_message ("IMAP Service sucessfully authenticated user %s", service->url->user);
authenticated = TRUE;
+ camel_imap_response_free (response);
}
}
/* Now lets find out the IMAP capabilities */
- status = camel_imap_command_extended (store, NULL, &response, ex, "CAPABILITY");
- if (status != CAMEL_IMAP_OK)
+ response = camel_imap_command (store, NULL, ex, "CAPABILITY");
+ if (!response)
return FALSE;
-
result = camel_imap_response_extract (response, "CAPABILITY", ex);
if (!result)
return FALSE;
@@ -277,8 +275,8 @@ imap_connect (CamelService *service, CamelException *ex)
g_free (result);
/* We now need to find out which directory separator this daemon uses */
- status = camel_imap_command_extended (store, NULL, &response, ex, "LIST \"\" \"\"");
- if (status != CAMEL_IMAP_OK)
+ response = camel_imap_command (store, NULL, ex, "LIST \"\" \"\"");
+ if (!response)
return FALSE;
result = camel_imap_response_extract (response, "LIST", ex);
if (!result)
@@ -308,10 +306,12 @@ static gboolean
imap_disconnect (CamelService *service, CamelException *ex)
{
CamelImapStore *store = CAMEL_IMAP_STORE (service);
-
+ CamelImapResponse *response;
+
/* send the logout command */
- camel_imap_command_extended (store, NULL, NULL, ex, "LOGOUT");
-
+ response = camel_imap_command (store, NULL, ex, "LOGOUT");
+ camel_imap_response_free (response);
+
g_free (store->dir_sep);
store->dir_sep = NULL;
@@ -342,9 +342,8 @@ camel_imap_store_folder_path (CamelImapStore *store, const char *name)
static gboolean
imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *selectable, CamelException *ex)
{
- GPtrArray *response;
+ CamelImapResponse *response;
char *result, *flags, *sep, *dirname;
- gint status;
if (!g_strcasecmp (folder_path, "INBOX")) {
if (selectable)
@@ -356,9 +355,9 @@ imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *se
if (selectable)
*selectable = FALSE;
- status = camel_imap_command_extended (CAMEL_IMAP_STORE (store), NULL,
- &response, ex, "LIST \"\" \"%s\"", folder_path);
- if (status != CAMEL_IMAP_OK)
+ response = camel_imap_command (store, NULL, ex,
+ "LIST \"\" \"%s\"", folder_path);
+ if (!response)
return FALSE;
result = camel_imap_response_extract (response, "LIST", ex);
if (!result)
@@ -387,12 +386,13 @@ imap_folder_exists (CamelImapStore *store, const char *folder_path, gboolean *se
static gboolean
imap_create (CamelImapStore *store, const char *folder_path, CamelException *ex)
{
- gint status;
+ CamelImapResponse *response;
- status = camel_imap_command_extended (store, NULL, NULL, ex,
- "CREATE \"%s\"", folder_path);
-
- return status == CAMEL_IMAP_OK;
+ response = camel_imap_command (store, NULL, ex,
+ "CREATE \"%s\"", folder_path);
+ camel_imap_response_free (response);
+
+ return !camel_exception_is_set (ex);
}
static CamelFolder *
@@ -485,8 +485,9 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
CamelURL *url = CAMEL_SERVICE (store)->url;
gboolean found_inbox = FALSE;
- int status, len, i;
- GPtrArray *response;
+ int len, i;
+ CamelImapResponse *response;
+ GPtrArray *folders;
char *dir_sep, *namespace, *base_url, *list;
CamelFolderInfo *topfi, *fi;
@@ -508,9 +509,9 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
base_url[len + 1] = '\0';
}
- status = camel_imap_command_extended (imap_store, NULL, &response, ex,
- "LIST \"\" \"%s\"", namespace);
- if (status != CAMEL_IMAP_OK) {
+ response = camel_imap_command (imap_store, NULL, ex,
+ "LIST \"\" \"%s\"", namespace);
+ if (!response) {
g_free (namespace);
g_free (base_url);
return NULL;
@@ -524,12 +525,11 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
topfi = parse_list_response_as_folder_info (list, namespace, base_url);
g_free (list);
- status = camel_imap_command_extended (imap_store, NULL, &response, ex,
- "LIST \"\" \"%s%s%c\"",
- namespace,
- *namespace ? dir_sep : "",
- recursive ? '*' : '%');
- if (status != CAMEL_IMAP_OK) {
+ response = camel_imap_command (imap_store, NULL, ex,
+ "LIST \"\" \"%s%s%c\"",
+ namespace, *namespace ? dir_sep : "",
+ recursive ? '*' : '%');
+ if (!response) {
g_free (namespace);
g_free (base_url);
return NULL;
@@ -538,21 +538,19 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
/* Turn responses into CamelFolderInfo and remove any
* extraneous responses.
*/
- for (i = 0; i < response->len; i++) {
- list = response->pdata[i];
- response->pdata[i] = fi =
- parse_list_response_as_folder_info (list, namespace,
- base_url);
- g_free (list);
-
- if (!response->pdata[i]) {
- g_ptr_array_remove_index_fast (response, i--);
+ folders = g_ptr_array_new ();
+ for (i = 0; i < response->untagged->len; i++) {
+ list = response->untagged->pdata[i];
+ fi = parse_list_response_as_folder_info (list, namespace,
+ base_url);
+ if (!fi)
continue;
- }
+ g_ptr_array_add (folders, fi);
if (!g_strcasecmp (fi->full_name, "INBOX"))
found_inbox = TRUE;
}
+ camel_imap_response_free (response);
/* Add INBOX, if necessary */
if (!*top && !found_inbox) {
@@ -562,12 +560,12 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
fi->url = g_strdup_printf ("%sINBOX", base_url);
/* FIXME: read/unread msg count */
- g_ptr_array_add (response, fi);
+ g_ptr_array_add (folders, fi);
}
/* And assemble */
- camel_folder_info_build (response, topfi, *dir_sep, TRUE);
- g_ptr_array_free (response, FALSE);
+ camel_folder_info_build (folders, topfi, *dir_sep, TRUE);
+ g_ptr_array_free (folders, FALSE);
/* Remove the top if it's the root of the store. */
if (!*top && !topfi->sibling) {
@@ -586,864 +584,8 @@ static void
imap_keepalive (CamelRemoteStore *store)
{
CamelImapStore *imap_store = CAMEL_IMAP_STORE (store);
-
- camel_imap_command_extended (imap_store, NULL, NULL, NULL, "NOOP");
-}
-
-static int
-camel_imap_status (char *cmdid, char *respbuf)
-{
- char *retcode;
-
- if (respbuf) {
- if (!strncmp (respbuf, cmdid, strlen (cmdid))) {
- retcode = imap_next_word (respbuf);
-
- if (!strncmp (retcode, "OK", 2))
- return CAMEL_IMAP_OK;
- else if (!strncmp (retcode, "NO", 2))
- return CAMEL_IMAP_NO;
- else if (!strncmp (retcode, "BAD", 3))
- return CAMEL_IMAP_BAD;
- }
- }
-
- return CAMEL_IMAP_FAIL;
-}
-
-static gint
-check_current_folder (CamelImapStore *store, CamelFolder *folder, char *fmt, CamelException *ex)
-{
- char *folder_path;
- int status;
-
- /* return OK if we meet one of the following criteria:
- * 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 ", 7))
- return CAMEL_IMAP_OK;
-
- folder_path = camel_imap_store_folder_path (store, folder->full_name);
- status = camel_imap_command_extended (store, NULL, NULL, ex, "SELECT \"%s\"", folder_path);
- g_free (folder_path);
-
- if (status != CAMEL_IMAP_OK) {
- store->current_folder = NULL;
- return status;
- }
-
- /* remember our currently selected folder */
- store->current_folder = folder;
-
- return CAMEL_IMAP_OK;
-}
-
-static gboolean
-send_command (CamelImapStore *store, char **cmdid, char *fmt, va_list ap, CamelException *ex)
-{
- gchar *cmdbuf;
-
- *cmdid = g_strdup_printf ("A%.5d", store->command++);
-
- cmdbuf = g_strdup_vprintf (fmt, ap);
-
- if (camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex, "%s %s\r\n", *cmdid, cmdbuf) < 0) {
- g_free (cmdbuf);
- g_free (*cmdid);
- *cmdid = NULL;
- return FALSE;
- }
-
- g_free (cmdbuf);
- return TRUE;
-}
-
-
-/**
- * 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, or %NULL
- * @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, GPtrArray **ret, CamelException *ex, char *fmt, ...)
-{
- gint status = CAMEL_IMAP_OK;
- GPtrArray *data = NULL;
- GArray *expunged;
- gchar *respbuf, *cmdid;
- 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;
-
- /* 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);
-
- expunged = g_array_new (FALSE, FALSE, sizeof (int));
- if (ret)
- 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 */
- if (ret) {
- for (i = 0; i < data->len; i++)
- g_free (data->pdata[i]);
- g_ptr_array_free (data, TRUE);
- }
- g_array_free (expunged, TRUE);
-
- return CAMEL_IMAP_FAIL;
- }
-
- /* 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);
- g_free (respbuf);
- continue;
- } 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_array_append_val (expunged, id);
- }
- g_free (respbuf);
- continue;
- }
- }
- if (ret)
- g_ptr_array_add (data, respbuf);
- else
- g_free (respbuf);
- }
-
- if (status == CAMEL_IMAP_OK) {
- if (ret)
- *ret = data;
- } 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");
- }
-
- if (ret) {
- for (i = 0; i < data->len; i++)
- g_free (data->pdata[i]);
- g_ptr_array_free (data, TRUE);
- }
- }
-
- if (respbuf)
- g_free (respbuf);
+ CamelImapResponse *response;
- /* Update the summary */
- if (folder && (recent > 0 || expunged->len > 0)) {
- CamelException dex;
-
- camel_exception_init (&dex);
- camel_imap_folder_changed (folder, recent, expunged, &dex);
- camel_exception_clear (&dex);
- }
- g_array_free (expunged, TRUE);
-
- return status;
-}
-
-/**
- * camel_imap_response_free:
- * @response: the result data returned from camel_imap_command_extended
- *
- * Frees the data.
- **/
-void
-camel_imap_response_free (GPtrArray *response)
-{
- int i;
-
- for (i = 0; i < response->len; i++)
- g_free (response->pdata[i]);
- g_ptr_array_free (response, TRUE);
-}
-
-/**
- * camel_imap_response_extract:
- * @response: the result data returned from camel_imap_command_extended
- * @type: the response type to extract
- * @ex: a CamelException
- *
- * This checks that @response contains a single untagged response of
- * type @type and returns just that response data. If @response
- * doesn't contain the right information, the function will set @ex and
- * return %NULL. Either way, @response will be freed.
- *
- * Return value: the desired response string, which the caller must free.
- **/
-char *
-camel_imap_response_extract (GPtrArray *response, const char *type,
- CamelException *ex)
-{
- int len = strlen (type), i;
- char *resp;
-
- for (i = 0; i < response->len; i++) {
- resp = response->pdata[i];
- if (strncmp (resp, "* ", 2) != 0) {
- g_free (resp);
- continue;
- }
-
- /* Skip inititial sequence number, if present */
- strtoul (resp + 2, &resp, 10);
- if (*resp == ' ')
- resp++;
-
- if (!g_strncasecmp (resp, type, len))
- break;
-
- g_free (resp);
- }
-
- if (i < response->len) {
- resp = response->pdata[i];
- for (i++; i < response->len; i++)
- g_free (response->pdata[i]);
- } else {
- resp = NULL;
- camel_exception_setv (ex, CAMEL_EXCEPTION_SERVICE_UNAVAILABLE,
- "IMAP server response did not contain "
- "%s information", type);
- }
-
- g_ptr_array_free (response, TRUE);
- return resp;
-}
-
-/**
- * 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, or %NULL
- * @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: 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;
- GArray *expunged;
- gboolean is_notification;
- gchar *respbuf, *cmdid;
- guint32 len = 0;
- gint partlen = 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 ();
-
- /* get first response line */
- if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) != -1) {
- char *p, *q;
-
- g_ptr_array_add (data, respbuf);
- len += strlen (respbuf) + 1;
-
- for (p = respbuf; *p && *p != '{' && *p != '"' && *p != '\n'; p++);
- switch (*p) {
- case '"':
- /* a quoted string - section 4.3 */
- p++;
- for (q = p; *q && *q != '"'; q++);
- partlen = (guint32) (q - p);
-
- is_notification = TRUE;
-
- break;
- case '{':
- /* a literal string - section 4.3 */
- partlen = atoi (p + 1);
-
- /* add len to partlen because the partlen
- doesn't count the first response buffer */
- partlen += len;
-
- is_notification = FALSE;
-
- break;
- default:
- /* bad input */
- g_ptr_array_free (data, TRUE);
- return CAMEL_IMAP_FAIL;
- }
- } else {
- g_ptr_array_free (data, TRUE);
- return CAMEL_IMAP_FAIL;
- }
-
- expunged = g_array_new (FALSE, FALSE, sizeof (int));
-
- /* 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);
- g_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 (is_notification && !strncmp (respbuf, cmdid, strlen (cmdid))) {
- status = camel_imap_status (cmdid, respbuf);
- break;
- }
-
- /* FIXME: this is redundant */
- /* 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_array_remove_index (expunged, i);
- }
-
- /* Check for a RECENT in the untagged response */
- if (*respbuf == '*' && is_notification) {
- 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_array_append_val (expunged, id);
- }
- }
- }
-
- if (!is_notification) {
- partlen--;
- if (len >= partlen)
- is_notification = TRUE;
- }
- }
-
- if (status == CAMEL_IMAP_OK && ret) {
- 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 if (status != CAMEL_IMAP_OK) {
- /* 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");
- }
-
- if (ret)
- *ret = NULL;
- }
-
- /* Update the summary */
- if (folder && (recent > 0 || expunged->len > 0)) {
- CamelException dex;
-
- camel_exception_init (&dex);
- camel_imap_folder_changed (folder, recent, expunged, &dex);
- camel_exception_clear (&dex);
- }
-
- for (i = 0; i < data->len; i++)
- g_free (data->pdata[i]);
- g_ptr_array_free (data, TRUE);
- g_array_free (expunged, TRUE);
-
- return status;
-}
-
-/**
- * camel_imap_command_preliminary: Send a preliminary command to the
- * IMAP server.
- * @store: the IMAP store
- * @cmdid: a pointer to return the command identifier (for use in
- * camel_imap_command_continuation)
- * @fmt: a printf-style format string, followed by arguments
- *
- * This camel method sends a preliminary IMAP command specified by
- * @fmt and the following arguments to the IMAP store specified by
- * @store. This function is meant for use with multi-transactional
- * IMAP communications like Kerberos authentication and APPEND.
- *
- * Return value: one of CAMEL_IMAP_PLUS, CAMEL_IMAP_NO, CAMEL_IMAP_BAD
- * or CAMEL_IMAP_FAIL
- *
- * Note: on success (CAMEL_IMAP_PLUS), you will need to follow up with
- * a camel_imap_command_continuation call.
- **/
-gint
-camel_imap_command_preliminary (CamelImapStore *store, char **cmdid, CamelException *ex, char *fmt, ...)
-{
- char *respbuf, *word;
- gint status = CAMEL_IMAP_OK;
- va_list ap;
-
- /* 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);
-
- /* read single line response */
- if (camel_remote_store_recv_line (CAMEL_REMOTE_STORE (store), &respbuf, ex) < 0)
- return CAMEL_IMAP_FAIL;
-
- /* Check for '+' which indicates server is ready for command continuation */
- if (*respbuf == '+')
- return CAMEL_IMAP_PLUS;
-
- status = camel_imap_status (*cmdid, respbuf);
-
- 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_continuation: Handle another transaction with the IMAP
- * server and possibly get a multi-line response.
- * @store: the IMAP store
- * @cmdid: The command identifier returned from camel_imap_command_preliminary
- * @ret: a pointer to return the full server response in, or %NULL
- * @cmdbuf: buffer containing the response/request data
- *
- * This method is for sending continuing responses to the IMAP server.
- * Meant to be used as a followup to camel_imap_command_preliminary.
- * If @ret is non-%NULL camel_imap_command_continuation will set it to
- * point to a buffer containing the rest of the response from the IMAP
- * server. The caller function is responsible for freeing @ret.
- *
- * Return value: one of CAMEL_IMAP_PLUS (command requires additional data),
- * 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_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;
- }
-
- 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 && ret) {
- 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 if (status != CAMEL_IMAP_OK) {
- /* 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");
- }
-
- if (ret)
- *ret = NULL;
- }
-
- /* cleanup */
- for (i = 0; i < data->len; i++)
- g_free (data->pdata[i]);
- g_ptr_array_free (data, TRUE);
-
- return status;
-}
-
-/**
- * camel_imap_command_continuation_with_stream: Handle another transaction with the IMAP
- * server and possibly get a multi-line response.
- * @store: the IMAP store
- * @cmdid: The command identifier returned from camel_imap_command_preliminary
- * @ret: a pointer to return the full server response in, or %NULL
- * @cstream: a CamelStream containing a continuation response.
- *
- * This method is for sending continuing responses to the IMAP server.
- * Meant to be used as a followup to camel_imap_command_preliminary.
- * If @ret is not %NULL, camel_imap_command_continuation will set it
- * to point to a buffer containing the rest of the response from the
- * IMAP server. The caller function is responsible for freeing @ret.
- *
- * Return value: one of CAMEL_IMAP_PLUS (command requires additional data),
- * 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_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;
- }
-
- 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 && ret) {
- 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 if (status != CAMEL_IMAP_OK) {
- /* 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 error");
- }
-
- if (ret)
- *ret = NULL;
- }
-
- /* cleanup */
- for (i = 0; i < data->len; i++)
- g_free (data->pdata[i]);
- g_ptr_array_free (data, TRUE);
-
- return status;
+ response = camel_imap_command (imap_store, NULL, NULL, "NOOP");
+ camel_imap_response_free (response);
}
diff --git a/camel/providers/imap/camel-imap-store.h b/camel/providers/imap/camel-imap-store.h
index 1d9a07ff96..3382a8940b 100644
--- a/camel/providers/imap/camel-imap-store.h
+++ b/camel/providers/imap/camel-imap-store.h
@@ -66,50 +66,6 @@ typedef struct {
} CamelImapStoreClass;
-/* public methods */
-void camel_imap_store_open (CamelImapStore *store, CamelException *ex);
-void camel_imap_store_close (CamelImapStore *store, gboolean expunge, CamelException *ex);
-
-/* support functions */
-
-enum {
- CAMEL_IMAP_OK = 0,
- CAMEL_IMAP_NO,
- CAMEL_IMAP_BAD,
- CAMEL_IMAP_PLUS,
- CAMEL_IMAP_FAIL
-};
-
-gint camel_imap_command (CamelImapStore *store, CamelFolder *folder,
- CamelException *ex, char *fmt, ...);
-
-gint camel_imap_command_extended (CamelImapStore *store, CamelFolder *folder,
- GPtrArray **ret, CamelException *ex, char *fmt, ...);
-void camel_imap_response_free (GPtrArray *response);
-char *camel_imap_response_extract (GPtrArray *response, const char *type,
- CamelException *ex);
-
-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,
- CamelException *ex,
- char *fmt, ...);
-
-gint camel_imap_command_continuation (CamelImapStore *store,
- char **ret,
- char *cmdid,
- char *cmdbuf,
- CamelException *ex);
-
-gint camel_imap_command_continuation_with_stream (CamelImapStore *store,
- char **ret,
- char *cmdid,
- CamelStream *cstream,
- CamelException *ex);
-
/* Standard Camel function */
CamelType camel_imap_store_get_type (void);
diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c
index 4658341e6a..98c8d63dd2 100644
--- a/camel/providers/imap/camel-imap-utils.c
+++ b/camel/providers/imap/camel-imap-utils.c
@@ -558,3 +558,77 @@ imap_parse_flag_list (const char *flag_list)
return flags;
}
+
+/**
+ * imap_parse_nstring:
+ * @str_p: a pointer to a string
+ * @len: a pointer to an int to return the length in
+ *
+ * This parses an "nstring" (NIL, a quoted string, or a literal)
+ * starting at *@str_p. On success, *@str_p will point to the first
+ * character after the end of the nstring, and *@len will contain
+ * the length of the returned string. On failure, *@str_p will be
+ * set to %NULL.
+ *
+ * This assumes that the string is in the form returned by
+ * camel_imap_command(): that line breaks are indicated by LF rather
+ * than CRLF.
+ *
+ * Return value: the parsed string, or %NULL if a NIL or no string
+ * was parsed. (In the former case, *@str_p will be %NULL; in the
+ * latter, it will point to the character after the NIL.)
+ **/
+char *
+imap_parse_nstring (char **str_p, int *len)
+{
+ char *str = *str_p;
+ char *out;
+
+ if (!str)
+ return NULL;
+ else if (*str == '"') {
+ char *p;
+ int size;
+
+ str++;
+ size = strcspn (str, "\"") + 1;
+ p = out = g_malloc (size);
+
+ while (*str && *str != '"') {
+ if (*str == '\\')
+ str++;
+ *p++ = *str++;
+ if (p - out == size) {
+ out = g_realloc (out, size * 2);
+ p = out + size;
+ size *= 2;
+ }
+ }
+ if (*str != '"') {
+ *str_p = NULL;
+ g_free (out);
+ return NULL;
+ }
+ *p = '\0';
+ *str_p = str + 1;
+ *len = strlen (out);
+ return out;
+ } else if (*str == '{') {
+ *len = strtoul (str + 1, (char **)&str, 10);
+ if (*str++ != '}' || *str++ != '\n' || strlen (str) < *len) {
+ *str_p = NULL;
+ return NULL;
+ }
+ out = g_strndup (str, *len);
+ *str_p = str + *len;
+ return out;
+ } else if (!g_strncasecmp (str, "nil", 3)) {
+ *str_p += 3;
+ *len = 0;
+ return NULL;
+ } else {
+ *str_p = NULL;
+ return NULL;
+ }
+}
+
diff --git a/camel/providers/imap/camel-imap-utils.h b/camel/providers/imap/camel-imap-utils.h
index b08c179926..28dea3cc9f 100644
--- a/camel/providers/imap/camel-imap-utils.h
+++ b/camel/providers/imap/camel-imap-utils.h
@@ -39,6 +39,8 @@ char *imap_translate_sexp (const char *expression);
char *imap_create_flag_list (guint32 flags);
guint32 imap_parse_flag_list (const char *flag_list);
+char *imap_parse_nstring (char **str_p, int *len);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */