dovecot: Added imap_parser_get_literal_size() and imap_parser_re...

dovecot at dovecot.org dovecot at dovecot.org
Thu Nov 8 18:38:28 EET 2007


details:   http://hg.dovecot.org/dovecot/rev/d145669ed45a
changeset: 6739:d145669ed45a
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Nov 08 18:38:24 2007 +0200
description:
Added imap_parser_get_literal_size() and imap_parser_read_last_literal() to
help continue parsing input after IMAP_ARG_LITERAL_SIZE when
IMAP_PARSE_FLAG_LITERAL_SIZE is used.

diffstat:

2 files changed, 95 insertions(+), 8 deletions(-)
src/lib-imap/imap-parser.c |   97 ++++++++++++++++++++++++++++++++++++++++----
src/lib-imap/imap-parser.h |    6 ++

diffs (201 lines):

diff -r c3e6d7d96f1a -r d145669ed45a src/lib-imap/imap-parser.c
--- a/src/lib-imap/imap-parser.c	Thu Nov 08 18:24:16 2007 +0200
+++ b/src/lib-imap/imap-parser.c	Thu Nov 08 18:38:24 2007 +0200
@@ -16,7 +16,8 @@ enum arg_parse_type {
 	ARG_PARSE_ATOM,
 	ARG_PARSE_STRING,
 	ARG_PARSE_LITERAL,
-	ARG_PARSE_LITERAL_DATA
+	ARG_PARSE_LITERAL_DATA,
+	ARG_PARSE_LITERAL_DATA_FORCED
 };
 
 struct imap_parser {
@@ -43,6 +44,7 @@ struct imap_parser {
 
 	unsigned int literal_skip_crlf:1;
 	unsigned int literal_nonsync:1;
+	unsigned int literal_size_return:1;
 	unsigned int eol:1;
 	unsigned int fatal_error:1;
 };
@@ -54,7 +56,8 @@ imap_parser_create(struct istream *input
 	struct imap_parser *parser;
 
 	parser = i_new(struct imap_parser, 1);
-        parser->pool = pool_alloconly_create("IMAP parser", 1024*10);
+	parser->pool = pool_alloconly_create(MEMPOOL_GROWING"IMAP parser",
+					     1024*10);
 	parser->input = input;
 	parser->output = output;
 	parser->max_line_size = max_line_size;
@@ -91,6 +94,7 @@ void imap_parser_reset(struct imap_parse
 
 	parser->literal_skip_crlf = FALSE;
 	parser->eol = FALSE;
+	parser->literal_size_return = FALSE;
 }
 
 const char *imap_parser_get_error(struct imap_parser *parser, bool *fatal)
@@ -205,7 +209,11 @@ static void imap_parser_save_arg(struct 
 				IMAP_ARG_LITERAL_SIZE_NONSYNC :
 				IMAP_ARG_LITERAL_SIZE;
 			arg->_data.literal_size = parser->literal_size;
-		} else if ((parser->flags &
+			break;
+		}
+		/* fall through */
+	case ARG_PARSE_LITERAL_DATA_FORCED:
+		if ((parser->flags &
 			    IMAP_PARSE_FLAG_LITERAL_TYPE) != 0) {
 			arg->type = IMAP_ARG_LITERAL;
 			arg->_data.str = p_strndup(parser->pool, data, size);
@@ -395,7 +403,8 @@ static int imap_parser_read_literal_data
 		i_assert(parser->cur_pos == 0);
 	}
 
-	if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0) {
+	if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0 ||
+	    parser->cur_type == ARG_PARSE_LITERAL_DATA_FORCED) {
 		/* now we just wait until we've read enough data */
 		if (data_size < parser->literal_size)
 			return FALSE;
@@ -407,9 +416,9 @@ static int imap_parser_read_literal_data
 		}
 	} else {
 		/* we want to save only literal size, not the literal itself. */
-		parser->eol = TRUE;
+		parser->literal_size_return = TRUE;
 		imap_parser_save_arg(parser, NULL, 0);
-		return TRUE;
+		return FALSE;
 	}
 }
 
@@ -489,6 +498,7 @@ static int imap_parser_read_arg(struct i
 
 		/* fall through */
 	case ARG_PARSE_LITERAL_DATA:
+	case ARG_PARSE_LITERAL_DATA_FORCED:
 		if (!imap_parser_read_literal_data(parser, data, data_size))
 			return FALSE;
 		break;
@@ -514,7 +524,7 @@ static int finish_line(struct imap_parse
 	i_stream_skip(parser->input, parser->cur_pos);
 	parser->cur_pos = 0;
 
-	if (parser->list_arg != NULL) {
+	if (parser->list_arg != NULL && !parser->literal_size_return) {
 		parser->error = "Missing ')'";
 		*args_r = NULL;
 		return -1;
@@ -537,6 +547,13 @@ int imap_parser_read_args(struct imap_pa
 			  const struct imap_arg **args_r)
 {
 	parser->flags = flags;
+
+	if (parser->literal_size_return) {
+		/* delete EOL */
+		array_delete(&parser->root_list,
+			     array_count(&parser->root_list)-1, 1);
+		parser->literal_size_return = FALSE;
+	}
 
 	while (!parser->eol && (count == 0 || IS_UNFINISHED(parser) ||
 				array_count(&parser->root_list) < count)) {
@@ -557,7 +574,8 @@ int imap_parser_read_args(struct imap_pa
 		*args_r = NULL;
 		return -1;
 	} else if ((!IS_UNFINISHED(parser) && count > 0 &&
-		    array_count(&parser->root_list) >= count) || parser->eol) {
+		    array_count(&parser->root_list) >= count) ||
+		   parser->eol || parser->literal_size_return) {
 		/* all arguments read / end of line. */
                 return finish_line(parser, count, args_r);
 	} else {
@@ -565,6 +583,69 @@ int imap_parser_read_args(struct imap_pa
 		*args_r = NULL;
 		return -2;
 	}
+}
+
+static struct imap_arg *
+imap_parser_get_last_literal_size(struct imap_parser *parser,
+				  ARRAY_TYPE(imap_arg_list) **list_r)
+{
+	ARRAY_TYPE(imap_arg_list) *list;
+	struct imap_arg *args;
+	unsigned int count;
+
+	list = &parser->root_list;
+	args = array_get_modifiable(&parser->root_list, &count);
+	i_assert(count > 1 && args[count-1].type == IMAP_ARG_EOL);
+	count--;
+
+	while (args[count-1].type != IMAP_ARG_LITERAL_SIZE &&
+	       args[count-1].type != IMAP_ARG_LITERAL_SIZE_NONSYNC) {
+		if (args[count-1].type != IMAP_ARG_LIST)
+			return NULL;
+
+		/* maybe the list ends with literal size */
+		list = &args[count-1]._data.list;
+		args = array_get_modifiable(list, &count);
+		if (count == 0)
+			return NULL;
+	}
+
+	*list_r = list;
+	return &args[count-1];
+}
+
+bool imap_parser_get_literal_size(struct imap_parser *parser, uoff_t *size_r)
+{
+	ARRAY_TYPE(imap_arg_list) *list;
+	struct imap_arg *last_arg;
+
+	last_arg = imap_parser_get_last_literal_size(parser, &list);
+	if (last_arg == NULL)
+		return FALSE;
+
+	*size_r = IMAP_ARG_LITERAL_SIZE(last_arg);
+	return TRUE;
+}
+
+void imap_parser_read_last_literal(struct imap_parser *parser)
+{
+	ARRAY_TYPE(imap_arg_list) *list;
+	struct imap_arg *last_arg;
+
+	i_assert(parser->literal_size_return);
+
+	last_arg = imap_parser_get_last_literal_size(parser, &list);
+	i_assert(last_arg != NULL);
+
+	parser->cur_type = ARG_PARSE_LITERAL_DATA_FORCED;
+	i_assert(parser->literal_size == last_arg->_data.literal_size);
+
+	/* delete EOL */
+	array_delete(&parser->root_list, array_count(&parser->root_list)-1, 1);
+
+	/* delete literal size */
+	array_delete(list, array_count(list)-1, 1);
+	parser->literal_size_return = FALSE;
 }
 
 int imap_parser_finish_line(struct imap_parser *parser, unsigned int count,
diff -r c3e6d7d96f1a -r d145669ed45a src/lib-imap/imap-parser.h
--- a/src/lib-imap/imap-parser.h	Thu Nov 08 18:24:16 2007 +0200
+++ b/src/lib-imap/imap-parser.h	Thu Nov 08 18:38:24 2007 +0200
@@ -119,6 +119,12 @@ int imap_parser_read_args(struct imap_pa
 int imap_parser_read_args(struct imap_parser *parser, unsigned int count,
 			  enum imap_parser_flags flags,
 			  const struct imap_arg **args_r);
+/* If parsing ended with literal size, return it. */
+bool imap_parser_get_literal_size(struct imap_parser *parser, uoff_t *size_r);
+/* IMAP_PARSE_FLAG_LITERAL_SIZE is set and last read argument was a literal.
+   Calling this function causes the literal size to be replaced with the actual
+   literal data when continuing argument parsing. */
+void imap_parser_read_last_literal(struct imap_parser *parser);
 
 /* just like imap_parser_read_args(), but assume \n at end of data in
    input stream. */


More information about the dovecot-cvs mailing list