[dovecot-cvs] dovecot/src/imap cmd-fetch.c, 1.23, 1.24 imap-fetch-body.c, 1.12, 1.13 imap-fetch.c, 1.26, 1.27 imap-fetch.h, 1.9, 1.10

cras at dovecot.org cras at dovecot.org
Tue Sep 28 13:55:39 EEST 2004


Update of /var/lib/cvs/dovecot/src/imap
In directory talvi:/tmp/cvs-serv1148/imap

Modified Files:
	cmd-fetch.c imap-fetch-body.c imap-fetch.c imap-fetch.h 
Log Message:
BODY.PEEK[HEADER.FIELDS (...)] list is allowed to contain strings and
literals. We didn't handle them correctly before.



Index: cmd-fetch.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/cmd-fetch.c,v
retrieving revision 1.23
retrieving revision 1.24
diff -u -d -r1.23 -r1.24
--- cmd-fetch.c	19 Sep 2004 23:23:08 -0000	1.23
+++ cmd-fetch.c	28 Sep 2004 10:55:36 -0000	1.24
@@ -6,45 +6,52 @@
 #include "imap-search.h"
 #include "mail-search.h"
 
+const char *all_macro[] = {
+	"FLAGS", "INTERNALDATE", "RFC822.SIZE", "ENVELOPE", NULL
+};
+const char *fast_macro[] = {
+	"FLAGS", "INTERNALDATE", "RFC822.SIZE", NULL
+};
+const char *full_macro[] = {
+	"FLAGS", "INTERNALDATE", "RFC822.SIZE", "ENVELOPE", "BODY", NULL
+};
+
 static int
 fetch_parse_args(struct client *client, struct imap_fetch_context *ctx,
 		 struct imap_arg *arg)
 {
-	const char *str;
+	const char *str, *const *macro;
 
 	if (arg->type == IMAP_ARG_ATOM) {
 		str = str_ucase(IMAP_ARG_STR(arg));
+		arg++;
 
 		/* handle macros first */
-		if (strcmp(str, "ALL") == 0) {
-			if (!imap_fetch_init_handler(ctx, "FLAGS") ||
-			    !imap_fetch_init_handler(ctx, "INTERNALDATE") ||
-			    !imap_fetch_init_handler(ctx, "RFC822.SIZE") ||
-			    !imap_fetch_init_handler(ctx, "ENVELOPE"))
-				return FALSE;
-		} else if (strcmp(str, "FAST") == 0) {
-			if (!imap_fetch_init_handler(ctx, "FLAGS") ||
-			    !imap_fetch_init_handler(ctx, "INTERNALDATE") ||
-			    !imap_fetch_init_handler(ctx, "RFC822.SIZE"))
-				return FALSE;
-		} else if (strcmp(str, "FULL") == 0) {
-			if (!imap_fetch_init_handler(ctx, "FLAGS") ||
-			    !imap_fetch_init_handler(ctx, "INTERNALDATE") ||
-			    !imap_fetch_init_handler(ctx, "RFC822.SIZE") ||
-			    !imap_fetch_init_handler(ctx, "ENVELOPE") ||
-			    !imap_fetch_init_handler(ctx, "BODY"))
-				return FALSE;
-		} else {
-			if (!imap_fetch_init_handler(ctx, str))
+		if (strcmp(str, "ALL") == 0)
+			macro = all_macro;
+		else if (strcmp(str, "FAST") == 0)
+			macro = fast_macro;
+		else if (strcmp(str, "FULL") == 0)
+			macro = full_macro;
+		else {
+			macro = NULL;
+			if (!imap_fetch_init_handler(ctx, str, &arg))
 				return FALSE;
 		}
+		if (macro != NULL) {
+			while (*macro != NULL) {
+				if (!imap_fetch_init_handler(ctx, *macro, &arg))
+					return FALSE;
+				macro++;
+			}
+		}
 	} else {
 		arg = IMAP_ARG_LIST(arg)->args;
 		while (arg->type == IMAP_ARG_ATOM) {
 			str = str_ucase(IMAP_ARG_STR(arg));
-			if (!imap_fetch_init_handler(ctx, str))
-				return FALSE;
 			arg++;
+			if (!imap_fetch_init_handler(ctx, str, &arg))
+				return FALSE;
 		}
 		if (arg->type != IMAP_ARG_EOL) {
 			client_send_command_error(client,
@@ -54,7 +61,7 @@
 	}
 
 	if (client->cmd_uid) {
-		if (!imap_fetch_init_handler(ctx, "UID"))
+		if (!imap_fetch_init_handler(ctx, "UID", &arg))
 			return FALSE;
 	}
 
@@ -122,7 +129,7 @@
 	const char *messageset;
 	int ret;
 
-	if (!client_read_args(client, 2, 0, &args))
+	if (!client_read_args(client, 0, 0, &args))
 		return FALSE;
 
 	if (!client_verify_open_mailbox(client))

Index: imap-fetch-body.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/imap-fetch-body.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- imap-fetch-body.c	23 Sep 2004 09:18:39 -0000	1.12
+++ imap-fetch-body.c	28 Sep 2004 10:55:36 -0000	1.13
@@ -3,12 +3,14 @@
 #include "common.h"
 #include "buffer.h"
 #include "str.h"
+#include "strescape.h"
 #include "istream.h"
 #include "ostream.h"
 #include "istream-header-filter.h"
 #include "message-parser.h"
 #include "message-send.h"
 #include "mail-storage.h"
+#include "imap-parser.h"
 #include "imap-fetch.h"
 
 #include <stdlib.h>
@@ -22,6 +24,10 @@
 	const char *section; /* NOTE: always uppercased */
 	uoff_t skip, max_size; /* if you don't want max_size,
 	                          set it to (uoff_t)-1 */
+
+	const char *const *fields;
+	size_t fields_count;
+
 	unsigned int skip_set:1;
 	unsigned int peek:1;
 };
@@ -37,24 +43,6 @@
 
 static struct partial_cache partial = { 0, 0, 0, 0, { 0, 0, 0 } };
 
-static const char *const *
-imap_fetch_get_body_fields(const char *fields, size_t *count_r)
-{
-	const char **arr, **p;
-	size_t count;
-
-	i_assert(*fields == '(');
-
-	arr = t_strsplit_spaces(t_strcut(fields+1, ')'), " ");
-	for (count = 0, p = arr; *p != NULL; p++)
-		count++;
-
-	qsort(arr, count, sizeof(*arr), strcasecmp_p);
-
-	*count_r = count;
-	return arr;
-}
-
 static int seek_partial(unsigned int select_counter, unsigned int uid,
 			struct partial_cache *partial, struct istream *stream,
 			uoff_t virtual_skip)
@@ -376,27 +364,23 @@
 				     const struct imap_fetch_body_data *body,
 				     const char *header_section)
 {
-	const char *const *fields;
 	struct message_size msg_size;
 	struct istream *input;
-	size_t fields_count;
 
 	/* MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */
 
 	ctx->cur_have_eoh = FALSE;
 	if (strncmp(header_section, "HEADER.FIELDS ", 14) == 0) {
-		fields = imap_fetch_get_body_fields(header_section + 14,
-						    &fields_count);
 		input = i_stream_create_header_filter(ctx->cur_input,
 						      HEADER_FILTER_INCLUDE,
-						      fields, fields_count,
+						      body->fields,
+						      body->fields_count,
 						      header_filter_eoh, ctx);
 	} else if (strncmp(header_section, "HEADER.FIELDS.NOT ", 18) == 0) {
-		fields = imap_fetch_get_body_fields(header_section + 18,
-						    &fields_count);
 		input = i_stream_create_header_filter(ctx->cur_input,
 						      HEADER_FILTER_EXCLUDE,
-						      fields, fields_count,
+						      body->fields,
+						      body->fields_count,
 						      header_filter_eoh, ctx);
 	} else if (strcmp(header_section, "MIME") == 0) {
 		/* Mime-Version + Content-* fields */
@@ -589,8 +573,7 @@
 					 struct imap_fetch_body_data *body,
 					 const char *section)
 {
-	const char *const *headers, *const *arr;
-	size_t count;
+	const char *const *arr;
 
 	if (!fetch_body_header_fields_check(section))
 		return FALSE;
@@ -604,14 +587,13 @@
 	}
 
 	t_push();
-        headers = imap_fetch_get_body_fields(section, &count);
 
-	for (arr = headers; *arr != NULL; arr++) {
+	for (arr = body->fields; *arr != NULL; arr++) {
 		char *hdr = p_strdup(ctx->client->cmd_pool, *arr);
 		buffer_append(ctx->all_headers_buf, &hdr, sizeof(hdr));
 	}
 
-	body->header_ctx = mailbox_header_lookup_init(ctx->box, headers);
+	body->header_ctx = mailbox_header_lookup_init(ctx->box, body->fields);
 	imap_fetch_add_handler(ctx, fetch_body_header_fields, body);
 	t_pop();
 	return TRUE;
@@ -698,11 +680,58 @@
 	return TRUE;
 }
 
-int fetch_body_section_init(struct imap_fetch_context *ctx, const char *arg)
+static int body_section_build(struct imap_fetch_context *ctx,
+			      struct imap_fetch_body_data *body,
+			      const char *prefix,
+			      const struct imap_arg_list *list)
+{
+	string_t *str;
+	const char **arr;
+	size_t i;
+
+	str = str_new(ctx->client->cmd_pool, 128);
+	str_append(str, prefix);
+	str_append(str, " (");
+
+	/* @UNSAFE: NULL-terminated list of headers */
+	arr = p_new(ctx->client->cmd_pool, const char *, list->size + 1);
+
+	for (i = 0; i < list->size; i++) {
+		if (list->args[i].type != IMAP_ARG_ATOM &&
+		    list->args[i].type != IMAP_ARG_STRING) {
+			client_send_command_error(ctx->client,
+				"Invalid BODY[..] parameter: "
+				"Header list contains non-strings");
+			return FALSE;
+		}
+
+		if (i != 0)
+			str_append_c(str, ' ');
+		arr[i] = str_ucase(IMAP_ARG_STR(&list->args[i]));
+
+		if (list->args[i].type == IMAP_ARG_ATOM)
+			str_append(str, arr[i]);
+		else {
+			str_append_c(str, '"');
+			str_append(str, str_escape(arr[i]));
+			str_append_c(str, '"');
+		}
+	}
+	str_append_c(str, ')');
+
+	qsort(arr, list->size, sizeof(*arr), strcasecmp_p);
+	body->fields = arr;
+	body->fields_count = list->size;
+	body->section = str_c(str);
+	return TRUE;
+}
+  
+int fetch_body_section_init(struct imap_fetch_context *ctx, const char *name,
+			    struct imap_arg **args)
 {
 	struct imap_fetch_body_data *body;
 	const char *partial;
-	const char *p = arg + 4;
+	const char *p = name + 4;
 
 	body = p_new(ctx->client->cmd_pool, struct imap_fetch_body_data, 1);
 	body->max_size = (uoff_t)-1;
@@ -720,14 +749,31 @@
 		return FALSE;
 	}
 
-	body->section = p+1;
-	p = strchr(body->section, ']');
-	if (p == NULL) {
-		client_send_command_error(ctx->client,
-			"Invalid BODY[..] parameter: Missing ']'");
-		return FALSE;
+	if ((*args)[0].type == IMAP_ARG_LIST) {
+		/* BODY[HEADER.FIELDS.. (headers list)] */
+		if ((*args)[1].type != IMAP_ARG_ATOM ||
+		    IMAP_ARG_STR(&(*args)[1])[0] != ']') {
+			client_send_command_error(ctx->client,
+				"Invalid BODY[..] parameter: Missing ']'");
+			return FALSE;
+		}
+		if (!body_section_build(ctx, body, p+1,
+					IMAP_ARG_LIST(&(*args)[0])))
+			return FALSE;
+		p = IMAP_ARG_STR(&(*args)[1]);
+		*args += 2;
+	} else {
+		/* no headers list */
+		body->section = p+1;
+		p = strchr(body->section, ']');
+		if (p == NULL) {
+			client_send_command_error(ctx->client,
+				"Invalid BODY[..] parameter: Missing ']'");
+			return FALSE;
+		}
+		body->section = p_strdup_until(ctx->client->cmd_pool,
+					       body->section, p);
 	}
-	body->section = p_strdup_until(ctx->client->cmd_pool, body->section, p);
 
 	if (*++p == '<') {
 		/* <start.end> */
@@ -860,9 +906,10 @@
 	return fetch_stream(ctx, &body_size);
 }
 
-int fetch_rfc822_init(struct imap_fetch_context *ctx, const char *arg)
+int fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name,
+		      struct imap_arg **args __attr_unused__)
 {
-	if (arg[6] == '\0') {
+	if (name[6] == '\0') {
 		ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER |
 			MAIL_FETCH_STREAM_BODY;
 		ctx->flags_update_seen = TRUE;
@@ -870,17 +917,17 @@
 		return TRUE;
 	}
 
-	if (strcmp(arg+6, ".SIZE") == 0) {
+	if (strcmp(name+6, ".SIZE") == 0) {
 		ctx->fetch_data |= MAIL_FETCH_VIRTUAL_SIZE;
 		imap_fetch_add_handler(ctx, fetch_rfc822_size, NULL);
 		return TRUE;
 	}
-	if (strcmp(arg+6, ".HEADER") == 0) {
+	if (strcmp(name+6, ".HEADER") == 0) {
 		ctx->fetch_data |= MAIL_FETCH_STREAM_HEADER;
 		imap_fetch_add_handler(ctx, fetch_rfc822_header, NULL);
 		return TRUE;
 	}
-	if (strcmp(arg+6, ".TEXT") == 0) {
+	if (strcmp(name+6, ".TEXT") == 0) {
 		ctx->fetch_data |= MAIL_FETCH_STREAM_BODY;
 		ctx->flags_update_seen = TRUE;
 		imap_fetch_add_handler(ctx, fetch_rfc822_text, NULL);
@@ -888,6 +935,6 @@
 	}
 
 	client_send_command_error(ctx->client, t_strconcat(
-		"Unknown parameter ", arg, NULL));
+		"Unknown parameter ", name, NULL));
 	return FALSE;
 }

Index: imap-fetch.c
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/imap-fetch.c,v
retrieving revision 1.26
retrieving revision 1.27
diff -u -d -r1.26 -r1.27
--- imap-fetch.c	19 Sep 2004 23:23:08 -0000	1.26
+++ imap-fetch.c	28 Sep 2004 10:55:36 -0000	1.27
@@ -58,22 +58,23 @@
 	return name[i] < 'A' || name[i] >= 'Z' ? 0 : -1;
 }
 
-int imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *arg)
+int imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
+			    struct imap_arg **args)
 {
 	const struct imap_fetch_handler *handler;
 
-	handler = bsearch(arg, fetch_handlers->data,
+	handler = bsearch(name, fetch_handlers->data,
 			  fetch_handlers->used /
 			  sizeof(struct imap_fetch_handler),
                           sizeof(struct imap_fetch_handler),
 			  imap_fetch_handler_bsearch);
 	if (handler == NULL) {
 		client_send_command_error(ctx->client,
-			t_strconcat("Unknown command ", arg, NULL));
+			t_strconcat("Unknown command ", name, NULL));
 		return FALSE;
 	}
 
-	return handler->init(ctx, arg);
+	return handler->init(ctx, name, args);
 }
 
 struct imap_fetch_context *imap_fetch_init(struct client *client)
@@ -136,7 +137,7 @@
 			ctx->flags_update_seen = FALSE;
 		else if (!ctx->flags_have_handler) {
 			ctx->flags_show_only_seen_changes = TRUE;
-			(void)imap_fetch_init_handler(ctx, "FLAGS");
+			(void)imap_fetch_init_handler(ctx, "FLAGS", NULL);
 		}
 	}
 
@@ -290,14 +291,15 @@
 	return 1;
 }
 
-static int fetch_body_init(struct imap_fetch_context *ctx, const char *arg)
+static int fetch_body_init(struct imap_fetch_context *ctx, const char *name,
+			   struct imap_arg **args)
 {
-	if (arg[4] == '\0') {
+	if (name[4] == '\0') {
 		ctx->fetch_data |= MAIL_FETCH_IMAP_BODY;
 		imap_fetch_add_handler(ctx, fetch_body, NULL);
 		return TRUE;
 	}
-	return fetch_body_section_init(ctx, arg);
+	return fetch_body_section_init(ctx, name, args);
 }
 
 static int fetch_bodystructure(struct imap_fetch_context *ctx,
@@ -325,7 +327,8 @@
 }
 
 static int fetch_bodystructure_init(struct imap_fetch_context *ctx,
-				    const char *arg __attr_unused__)
+				    const char *name __attr_unused__,
+				    struct imap_arg **args __attr_unused__)
 {
 	ctx->fetch_data |= MAIL_FETCH_IMAP_BODYSTRUCTURE;
 	imap_fetch_add_handler(ctx, fetch_bodystructure, NULL);
@@ -356,7 +359,8 @@
 }
 
 static int fetch_envelope_init(struct imap_fetch_context *ctx,
-			       const char *arg __attr_unused__)
+			       const char *name __attr_unused__,
+			       struct imap_arg **args __attr_unused__)
 {
 	ctx->fetch_data |= MAIL_FETCH_IMAP_ENVELOPE;
 	imap_fetch_add_handler(ctx, fetch_envelope, NULL);
@@ -392,7 +396,8 @@
 }
 
 static int fetch_flags_init(struct imap_fetch_context *ctx,
-			    const char *arg __attr_unused__)
+			    const char *name __attr_unused__,
+			    struct imap_arg **args __attr_unused__)
 {
 	ctx->flags_have_handler = TRUE;
 	ctx->fetch_data |= MAIL_FETCH_FLAGS;
@@ -416,7 +421,8 @@
 
 
 static int fetch_internaldate_init(struct imap_fetch_context *ctx,
-				   const char *arg __attr_unused__)
+				   const char *name __attr_unused__,
+				   struct imap_arg **args __attr_unused__)
 {
 	ctx->fetch_data |= MAIL_FETCH_RECEIVED_DATE;
 	imap_fetch_add_handler(ctx, fetch_internaldate, NULL);
@@ -431,7 +437,8 @@
 }
 
 static int fetch_uid_init(struct imap_fetch_context *ctx __attr_unused__,
-			  const char *arg __attr_unused__)
+			  const char *name __attr_unused__,
+			  struct imap_arg **args __attr_unused__)
 {
 	imap_fetch_add_handler(ctx, fetch_uid, NULL);
 	return TRUE;

Index: imap-fetch.h
===================================================================
RCS file: /var/lib/cvs/dovecot/src/imap/imap-fetch.h,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- imap-fetch.h	22 Aug 2004 09:52:11 -0000	1.9
+++ imap-fetch.h	28 Sep 2004 10:55:37 -0000	1.10
@@ -12,7 +12,8 @@
 	const char *name;
 
 	/* Returns FALSE if arg is invalid. */
-	int (*init)(struct imap_fetch_context *ctx, const char *arg);
+	int (*init)(struct imap_fetch_context *ctx, const char *name,
+		    struct imap_arg **args);
 };
 
 struct imap_fetch_context_handler {
@@ -63,13 +64,16 @@
 
 struct imap_fetch_context *imap_fetch_init(struct client *client);
 int imap_fetch_deinit(struct imap_fetch_context *ctx);
-int imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *arg);
+int imap_fetch_init_handler(struct imap_fetch_context *ctx, const char *name,
+			    struct imap_arg **args);
 
 void imap_fetch_begin(struct imap_fetch_context *ctx,
 		      struct mail_search_arg *search_arg);
 int imap_fetch(struct imap_fetch_context *ctx);
 
-int fetch_body_section_init(struct imap_fetch_context *ctx, const char *arg);
-int fetch_rfc822_init(struct imap_fetch_context *ctx, const char *arg);
+int fetch_body_section_init(struct imap_fetch_context *ctx, const char *name,
+			    struct imap_arg **args);
+int fetch_rfc822_init(struct imap_fetch_context *ctx, const char *name,
+		      struct imap_arg **args);
 
 #endif



More information about the dovecot-cvs mailing list