Mercurial > dovecot > original-hg > dovecot-1.2
changeset 6739:d145669ed45a HEAD
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.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 08 Nov 2007 18:38:24 +0200 |
parents | c3e6d7d96f1a |
children | 23afbedda4af |
files | src/lib-imap/imap-parser.c src/lib-imap/imap-parser.h |
diffstat | 2 files changed, 95 insertions(+), 8 deletions(-) [+] |
line wrap: on
line diff
--- 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ } } 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 @@ /* 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 @@ 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; @@ -538,6 +548,13 @@ { 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)) { if (!imap_parser_read_arg(parser)) @@ -557,7 +574,8 @@ *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 { @@ -567,6 +585,69 @@ } } +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, enum imap_parser_flags flags, const struct imap_arg **args_r)
--- 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_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. */