aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--camel/ChangeLog19
-rw-r--r--camel/providers/imap/camel-imap-command.c123
-rw-r--r--camel/providers/imap/camel-imap-folder.c6
-rw-r--r--camel/providers/imap/camel-imap-store.c30
-rw-r--r--camel/providers/imap/camel-imap-utils.c35
-rw-r--r--camel/providers/imap/camel-imap-utils.h2
6 files changed, 194 insertions, 21 deletions
diff --git a/camel/ChangeLog b/camel/ChangeLog
index a41a94277e..370f21b528 100644
--- a/camel/ChangeLog
+++ b/camel/ChangeLog
@@ -1,3 +1,22 @@
+2000-12-15 Dan Winship <danw@helixcode.com>
+
+ * providers/imap/camel-imap-command.c (camel_imap_command): Change
+ the semantics of fmt: Now %S (capital S) means an IMAP "string",
+ (which can be sent as either a quoted string or a literal). If
+ the server supports LITERAL+, these will be sent as extended
+ literals (which don't require any special escaping). Otherwise
+ they'll be sent as quoted strings (and it now properly deals with
+ " or \ in the string).
+ (imap_command_strdup_vprintf): Utility routine that does the real
+ work for the functionality mentioned above.
+
+ * providers/imap/camel-imap-utils.c (imap_quote_string): Turns a
+ string into a proper IMAP "quoted string".
+
+ * providers/imap/camel-imap-store.c:
+ * providers/imap/camel-imap-folder.c: Use %S instead of "%s" where
+ appropriate.
+
2000-12-15 Jeffrey Stedfast <fejj@helixcode.com>
* camel-mime-utils.c (header_fold): When checking to see if we
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;
+}
diff --git a/camel/providers/imap/camel-imap-folder.c b/camel/providers/imap/camel-imap-folder.c
index c127df73de..ae3fe15822 100644
--- a/camel/providers/imap/camel-imap-folder.c
+++ b/camel/providers/imap/camel-imap-folder.c
@@ -469,7 +469,7 @@ imap_append_message (CamelFolder *folder, CamelMimeMessage *message,
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}",
+ response = camel_imap_command (store, NULL, ex, "APPEND %S%s%s {%d}",
folder->full_name, flagstr ? " " : "",
flagstr ? flagstr : "", ba->len);
g_free (flagstr);
@@ -501,7 +501,7 @@ imap_copy_message_to (CamelFolder *source, const char *uid,
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
CamelImapResponse *response;
- response = camel_imap_command (store, source, ex, "UID COPY %s \"%s\"",
+ response = camel_imap_command (store, source, ex, "UID COPY %s %S",
uid, destination->full_name);
camel_imap_response_free (response);
@@ -521,7 +521,7 @@ imap_move_message_to (CamelFolder *source, const char *uid,
CamelImapStore *store = CAMEL_IMAP_STORE (source->parent_store);
CamelImapResponse *response;
- response = camel_imap_command (store, source, ex, "UID COPY %s \"%s\"",
+ response = camel_imap_command (store, source, ex, "UID COPY %s %S",
uid, destination->full_name);
camel_imap_response_free (response);
diff --git a/camel/providers/imap/camel-imap-store.c b/camel/providers/imap/camel-imap-store.c
index 729452f002..6a87aec3ad 100644
--- a/camel/providers/imap/camel-imap-store.c
+++ b/camel/providers/imap/camel-imap-store.c
@@ -352,7 +352,7 @@ imap_connect (CamelService *service, CamelException *ex)
}
response = camel_imap_command (store, NULL, ex,
- "LOGIN \"%s\" \"%s\"",
+ "LOGIN %S %S",
service->url->user,
service->url->passwd);
if (!response) {
@@ -385,7 +385,7 @@ imap_connect (CamelService *service, CamelException *ex)
* for the given path, even if that path doesn't exist.
*/
response = camel_imap_command (store, NULL, ex,
- "LIST \"%s\" \"\"",
+ "LIST %S \"\"",
namespace);
} else {
/* Plain IMAP4 doesn't have that idiom, so we fall back
@@ -393,7 +393,7 @@ imap_connect (CamelService *service, CamelException *ex)
* the folder doesn't exist (eg, if namespace is "").
*/
response = camel_imap_command (store, NULL, ex,
- "LIST \"\" \"%s\"",
+ "LIST \"\" %S",
namespace);
}
if (!response)
@@ -457,7 +457,7 @@ imap_folder_exists (CamelImapStore *store, const char *folder_name,
return TRUE;
}
- response = camel_imap_command (store, NULL, ex, "LIST \"\" \"%s\"",
+ response = camel_imap_command (store, NULL, ex, "LIST \"\" %S",
folder_name);
if (!response)
return FALSE;
@@ -487,7 +487,7 @@ imap_create (CamelImapStore *store, const char *folder_name,
{
CamelImapResponse *response;
- response = camel_imap_command (store, NULL, ex, "CREATE \"%s\"",
+ response = camel_imap_command (store, NULL, ex, "CREATE %S",
folder_name);
camel_imap_response_free (response);
@@ -622,7 +622,7 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
name = "";
}
response = camel_imap_command (imap_store, NULL, ex,
- "LIST \"\" \"%s\"", name);
+ "LIST \"\" %S", name);
if (!response)
return FALSE;
list = camel_imap_response_extract (response, "LIST", ex);
@@ -637,15 +637,17 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
}
if (!top && subscribed_only)
- pattern = g_strdup ("");
+ pattern = g_strdup (recursive ? "*" : "%");
else if (*name)
- pattern = g_strdup_printf ("%s%c", name, imap_store->dir_sep);
+ pattern = g_strdup_printf ("%s%c%c", name, imap_store->dir_sep,
+ recursive ? '*' : '%');
else
- pattern = g_strdup (name);
+ pattern = g_strdup_printf ("%s%c", name,
+ recursive ? '*' : '%');
response = camel_imap_command (imap_store, NULL, ex,
- "%s \"\" \"%s%c\"",
+ "%s \"\" %S",
subscribed_only ? "LSUB" : "LIST",
- pattern, recursive ? '*' : '%');
+ pattern);
g_free (pattern);
if (!response)
return NULL;
@@ -696,7 +698,7 @@ get_folder_info (CamelStore *store, const char *top, gboolean fast,
response = camel_imap_command (
imap_store, NULL, NULL,
- "STATUS \"%s\" (MESSAGES UNSEEN)",
+ "STATUS %S (MESSAGES UNSEEN)",
fi->full_name);
if (!response)
continue;
@@ -749,7 +751,7 @@ subscribe_folder (CamelStore *store, const char *folder_name,
CamelImapResponse *response;
response = camel_imap_command (imap_store, NULL, ex,
- "SUBSCRIBE \"%s\"", folder_name);
+ "SUBSCRIBE %S", folder_name);
if (response) {
g_hash_table_insert (imap_store->subscribed_folders,
g_strdup (folder_name),
@@ -767,7 +769,7 @@ unsubscribe_folder (CamelStore *store, const char *folder_name,
gpointer key, value;
response = camel_imap_command (imap_store, NULL, ex,
- "UNSUBSCRIBE \"%s\"", folder_name);
+ "UNSUBSCRIBE %S", folder_name);
if (response) {
g_hash_table_lookup_extended (imap_store->subscribed_folders,
folder_name, &key, &value);
diff --git a/camel/providers/imap/camel-imap-utils.c b/camel/providers/imap/camel-imap-utils.c
index 0b947e07da..05c9d01d5e 100644
--- a/camel/providers/imap/camel-imap-utils.c
+++ b/camel/providers/imap/camel-imap-utils.c
@@ -687,3 +687,38 @@ imap_parse_astring (char **str_p, int *len)
*str_p += *len;
return p;
}
+
+/**
+ * imap_quote_string:
+ * @str: the string to quote, which must not contain CR or LF
+ *
+ * Return value: an IMAP "quoted" corresponding to the string, which
+ * the caller must free.
+ **/
+char *
+imap_quote_string (const char *str)
+{
+ const char *p;
+ char *quoted, *q;
+ int len;
+
+ len = strlen (str);
+ p = str;
+ while ((p = strpbrk (p, "\"\\"))) {
+ len++;
+ p++;
+ }
+
+ quoted = q = g_malloc (len + 3);
+ *q++ = '"';
+ while ((p = strpbrk (str, "\"\\"))) {
+ memcpy (q, str, p - str);
+ q += p - str;
+ *q++ = '\\';
+ *q++ = *p++;
+ str = p;
+ }
+ sprintf (q, "%s\"", str);
+
+ return quoted;
+}
diff --git a/camel/providers/imap/camel-imap-utils.h b/camel/providers/imap/camel-imap-utils.h
index d0cc05832d..e7b009f426 100644
--- a/camel/providers/imap/camel-imap-utils.h
+++ b/camel/providers/imap/camel-imap-utils.h
@@ -46,6 +46,8 @@ guint32 imap_parse_flag_list (const char *flag_list);
char *imap_parse_nstring (char **str_p, int *len);
char *imap_parse_astring (char **str_p, int *len);
+char *imap_quote_string (const char *str);
+
#ifdef __cplusplus
}
#endif /* __cplusplus */