dovecot-2.2: lib-imap: Added IMAP_PARSE_FLAG_SERVER_TEXT that fi...
dovecot at dovecot.org
dovecot at dovecot.org
Wed Sep 26 18:01:29 EEST 2012
details: http://hg.dovecot.org/dovecot-2.2/rev/382df961f290
changeset: 15129:382df961f290
user: Timo Sirainen <tss at iki.fi>
date: Tue Sep 11 20:44:37 2012 +0300
description:
lib-imap: Added IMAP_PARSE_FLAG_SERVER_TEXT that fixes parsing input from IMAP server.
diffstat:
src/lib-imap/imap-parser.c | 78 +++++++++++++++++++++++++++++++++++++++++++++-
src/lib-imap/imap-parser.h | 6 ++-
2 files changed, 82 insertions(+), 2 deletions(-)
diffs (160 lines):
diff -r 3e1f1b6887c8 -r 382df961f290 src/lib-imap/imap-parser.c
--- a/src/lib-imap/imap-parser.c Tue Sep 11 19:14:09 2012 +0300
+++ b/src/lib-imap/imap-parser.c Tue Sep 11 20:44:37 2012 +0300
@@ -17,7 +17,8 @@
ARG_PARSE_STRING,
ARG_PARSE_LITERAL,
ARG_PARSE_LITERAL_DATA,
- ARG_PARSE_LITERAL_DATA_FORCED
+ ARG_PARSE_LITERAL_DATA_FORCED,
+ ARG_PARSE_TEXT
};
struct imap_parser {
@@ -37,6 +38,7 @@
enum arg_parse_type cur_type;
size_t cur_pos; /* parser position in input buffer */
+ bool cur_resp_text; /* we're parsing [resp-text-code] */
int str_first_escape; /* ARG_PARSE_STRING: index to first '\' */
uoff_t literal_size; /* ARG_PARSE_LITERAL: string size */
@@ -100,6 +102,7 @@
parser->cur_type = ARG_PARSE_NONE;
parser->cur_pos = 0;
+ parser->cur_resp_text = FALSE;
parser->str_first_escape = 0;
parser->literal_size = 0;
@@ -210,6 +213,7 @@
switch (parser->cur_type) {
case ARG_PARSE_ATOM:
+ case ARG_PARSE_TEXT:
if (size == 3 && memcmp(data, "NIL", 3) == 0) {
/* NIL argument */
arg->type = IMAP_ARG_NIL;
@@ -468,6 +472,56 @@
}
}
+static bool imap_parser_is_next_resp_text(struct imap_parser *parser)
+{
+ const struct imap_arg *arg;
+
+ if (parser->cur_list != &parser->root_list ||
+ array_count(parser->cur_list) != 1)
+ return FALSE;
+
+ arg = array_idx(&parser->root_list, 0);
+ if (arg->type != IMAP_ARG_ATOM)
+ return FALSE;
+
+ return strcasecmp(arg->_data.str, "OK") == 0 ||
+ strcasecmp(arg->_data.str, "NO") == 0 ||
+ strcasecmp(arg->_data.str, "BAD") == 0 ||
+ strcasecmp(arg->_data.str, "BYE") == 0;
+}
+
+static bool imap_parser_is_next_text(struct imap_parser *parser)
+{
+ const struct imap_arg *arg;
+ unsigned int len;
+
+ if (parser->cur_list != &parser->root_list)
+ return FALSE;
+
+ arg = array_idx(&parser->root_list, array_count(&parser->root_list)-1);
+ if (arg->type != IMAP_ARG_ATOM)
+ return FALSE;
+
+ len = strlen(arg->_data.str);
+ return len > 0 && arg->_data.str[len-1] == ']';
+}
+
+static bool imap_parser_read_text(struct imap_parser *parser,
+ const unsigned char *data, size_t data_size)
+{
+ size_t i;
+
+ /* read until end of line */
+ for (i = parser->cur_pos; i < data_size; i++) {
+ if (is_linebreak(data[i])) {
+ imap_parser_save_arg(parser, data, i);
+ break;
+ }
+ }
+ parser->cur_pos = i;
+ return parser->cur_type == ARG_PARSE_NONE;
+}
+
/* Returns TRUE if argument was fully processed. Also returns TRUE if
an argument inside a list was processed. */
static int imap_parser_read_arg(struct imap_parser *parser)
@@ -485,6 +539,13 @@
return FALSE;
i_assert(parser->cur_pos == 0);
+ if (parser->cur_resp_text &&
+ imap_parser_is_next_text(parser)) {
+ /* we just parsed [resp-text-code] */
+ parser->cur_type = ARG_PARSE_TEXT;
+ break;
+ }
+
switch (data[0]) {
case '\r':
if (data_size == 1) {
@@ -538,6 +599,16 @@
case ARG_PARSE_ATOM:
if (!imap_parser_read_atom(parser, data, data_size))
return FALSE;
+ if ((parser->flags & IMAP_PARSE_FLAG_SERVER_TEXT) == 0)
+ break;
+
+ if (imap_parser_is_next_resp_text(parser)) {
+ /* we just parsed OK/NO/BAD/BYE. after parsing the
+ [resp-text-code] the rest of the message can contain
+ pretty much any random text, which we can't parse
+ as if it was valid IMAP input */
+ parser->cur_resp_text = TRUE;
+ }
break;
case ARG_PARSE_STRING:
if (!imap_parser_read_string(parser, data, data_size))
@@ -557,6 +628,10 @@
if (!imap_parser_read_literal_data(parser, data, data_size))
return FALSE;
break;
+ case ARG_PARSE_TEXT:
+ if (!imap_parser_read_text(parser, data, data_size))
+ return FALSE;
+ break;
default:
i_unreached();
}
@@ -579,6 +654,7 @@
parser->line_size += parser->cur_pos;
i_stream_skip(parser->input, parser->cur_pos);
parser->cur_pos = 0;
+ parser->cur_resp_text = FALSE;
if (parser->list_arg != NULL && !parser->literal_size_return) {
parser->error = "Missing ')'";
diff -r 3e1f1b6887c8 -r 382df961f290 src/lib-imap/imap-parser.h
--- a/src/lib-imap/imap-parser.h Tue Sep 11 19:14:09 2012 +0300
+++ b/src/lib-imap/imap-parser.h Tue Sep 11 20:44:37 2012 +0300
@@ -16,7 +16,11 @@
/* Don't check if atom contains invalid characters */
IMAP_PARSE_FLAG_ATOM_ALLCHARS = 0x08,
/* Allow strings to contain CRLFs */
- IMAP_PARSE_FLAG_MULTILINE_STR = 0x10
+ IMAP_PARSE_FLAG_MULTILINE_STR = 0x10,
+ /* We're parsing IMAP server replies. Parse the "text" after
+ OK/NO/BAD/BYE replies as a single atom. We assume that the initial
+ "*" or tag was already skipped over. */
+ IMAP_PARSE_FLAG_SERVER_TEXT = 0x20
};
struct imap_parser;
More information about the dovecot-cvs
mailing list