aboutsummaryrefslogtreecommitdiffstats
path: root/camel/providers/imap/camel-imap-command.c
diff options
context:
space:
mode:
Diffstat (limited to 'camel/providers/imap/camel-imap-command.c')
-rw-r--r--camel/providers/imap/camel-imap-command.c123
1 files changed, 119 insertions, 4 deletions
diff --git a/camel/providers/imap/camel-imap-command.c b/camel/providers/imap/camel-imap-command.c
index f490ec0e1f..b61c9f8cd3 100644
--- a/camel/providers/imap/camel-imap-command.c
+++ b/camel/providers/imap/camel-imap-command.c
@@ -27,6 +27,7 @@
#include <config.h>
+#include <stdarg.h>
#include <stdio.h>
#include <string.h>
@@ -39,6 +40,8 @@ static char *imap_read_untagged (CamelImapStore *store, char *line,
CamelException *ex);
static CamelImapResponse *imap_read_response (CamelImapStore *store,
CamelException *ex);
+static char *imap_command_strdup_vprintf (CamelImapStore *store,
+ const char *fmt, va_list ap);
/**
* camel_imap_command: Send a command to a IMAP server and get a response
@@ -46,7 +49,7 @@ static CamelImapResponse *imap_read_response (CamelImapStore *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
+ * @fmt: an sort of printf-style format string, followed by arguments
*
* This function makes sure that @folder (if non-%NULL) is the
* currently-selected folder on @store and then sends the IMAP command
@@ -56,6 +59,14 @@ static CamelImapResponse *imap_read_response (CamelImapStore *store,
* As a special case, if @fmt is %NULL, it will just select @folder
* and return the response from doing so.
*
+ * @fmt can include the following %-escapes ONLY:
+ * %s, %d, %%: as with printf
+ * %S: an IMAP "string" (quoted string or literal)
+ *
+ * %S strings will be passed as literals if the server supports LITERAL+
+ * and quoted strings otherwise. (%S does not support strings that
+ * contain newlines.)
+ *
* 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().
@@ -72,8 +83,7 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder,
CamelImapResponse *response;
store->current_folder = NULL;
- response = camel_imap_command (store, NULL, ex,
- "SELECT \"%s\"",
+ response = camel_imap_command (store, NULL, ex, "SELECT %S",
folder->full_name);
if (!response)
return NULL;
@@ -87,7 +97,7 @@ camel_imap_command (CamelImapStore *store, CamelFolder *folder,
/* Send the command */
va_start (ap, fmt);
- cmdbuf = g_strdup_vprintf (fmt, ap);
+ cmdbuf = imap_command_strdup_vprintf (store, fmt, ap);
va_end (ap);
camel_remote_store_send_string (CAMEL_REMOTE_STORE (store), ex,
@@ -445,3 +455,108 @@ camel_imap_response_extract_continuation (CamelImapResponse *response,
camel_imap_response_free (response);
return NULL;
}
+
+
+static char *
+imap_command_strdup_vprintf (CamelImapStore *store, const char *fmt,
+ va_list ap)
+{
+ GPtrArray *args;
+ const char *p, *start;
+ char *out, *op, *string;
+ int num, len, i;
+
+ args = g_ptr_array_new ();
+
+ /* Determine the length of the data */
+ len = strlen (fmt);
+ p = start = fmt;
+ while (*p) {
+ p = strchr (start, '%');
+ if (!p)
+ break;
+
+ switch (*++p) {
+ case 'd':
+ num = va_arg (ap, int);
+ g_ptr_array_add (args, GINT_TO_POINTER (num));
+ start = p + 1;
+ len += 10;
+ break;
+
+ case 's':
+ string = va_arg (ap, char *);
+ g_ptr_array_add (args, string);
+ start = p + 1;
+ len += strlen (string);
+ break;
+
+ case 'S':
+ string = va_arg (ap, char *);
+ g_ptr_array_add (args, string);
+ if (store->capabilities & IMAP_CAPABILITY_LITERALPLUS)
+ len += strlen (string) + 15;
+ else
+ len += strlen (string) * 2;
+ start = p + 1;
+ break;
+
+ case '%':
+ start = p;
+ break;
+
+ default:
+ g_warning ("camel-imap-command is not printf. I don't "
+ "know what '%%%c' means.", *p);
+ start = *p ? p + 1 : p;
+ break;
+ }
+ }
+
+ /* Now write out the string */
+ op = out = g_malloc (len);
+ p = start = fmt;
+ i = 0;
+ while (*p) {
+ p = strchr (start, '%');
+ if (!p) {
+ strcpy (op, start);
+ break;
+ } else {
+ strncpy (op, start, p - start);
+ op += p - start;
+ }
+
+ switch (*++p) {
+ case 'd':
+ num = GPOINTER_TO_INT (args->pdata[i++]);
+ op += sprintf (op, "%d", num);
+ break;
+
+ case 's':
+ string = args->pdata[i++];
+ op += sprintf (op, "%s", string);
+ break;
+
+ case 'S':
+ string = args->pdata[i++];
+ if (store->capabilities & IMAP_CAPABILITY_LITERALPLUS) {
+ op += sprintf (op, "{%d+}\r\n%s",
+ strlen (string), string);
+ } else {
+ char *quoted = imap_quote_string (string);
+ op += sprintf (op, "%s", quoted);
+ g_free (quoted);
+ }
+ break;
+
+ default:
+ *op++ = '%';
+ *op++ = *p;
+ }
+
+ start = *p ? p + 1 : p;
+ }
+
+ return out;
+}