diff --git a/lib/imap.c b/lib/imap.c index 4c9d14232a..4ef055c13d 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -236,6 +236,34 @@ static char *imap_atom(const char *str, bool escape_only) return curlx_dyn_ptr(&line); } +/* + * Finds the start of a literal '{size}' in line, skipping over quoted strings. + */ +static const char *imap_find_literal(const char *line, size_t len) +{ + const char *end = line + len; + bool in_quote = FALSE; + + while(line < end) { + if(in_quote) { + if(*line == '\\' && (line + 1) < end) { + line += 2; + continue; + } + if(*line == '"') + in_quote = FALSE; + } + else { + if(*line == '"') + in_quote = TRUE; + else if(*line == '{') + return line; + } + line++; + } + return NULL; +} + /*********************************************************************** * * imap_matchresp() @@ -1168,7 +1196,7 @@ static CURLcode imap_state_listsearch_resp(struct Curl_easy *data, body data). Literal syntax is {size}\r\n */ const char *cr = memchr(line, '\r', len); size_t line_len = cr ? (size_t)(cr - line) : len; - const char *ptr = memchr(line, '{', line_len); + const char *ptr = imap_find_literal(line, line_len); if(ptr) { curl_off_t size = 0; bool parsed = FALSE; @@ -1347,7 +1375,7 @@ static CURLcode imap_state_fetch_resp(struct Curl_easy *data, /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse the continuation data contained within the curly brackets */ - ptr = memchr(ptr, '{', len); + ptr = imap_find_literal(ptr, len); if(ptr) { ptr++; if(!curlx_str_number(&ptr, &size, CURL_OFF_T_MAX) && diff --git a/tests/data/test3206 b/tests/data/test3206 index 90c5b02c0b..8665e6207f 100644 --- a/tests/data/test3206 +++ b/tests/data/test3206 @@ -15,7 +15,7 @@ CUSTOMREQUEST %repeat[120 x Testing large IMAP literal with custom FETCH. XXXXXXXXXXXXX%0d]% -* 456 FETCH (BODY[TEXT] {7201}%CR +* 456 FETCH (("fake {50}" BODY[TEXT]) {7201}%CR %repeat[120 x Testing large IMAP literal with custom FETCH. XXXXXXXXXXXXX%0d]% @@ -28,8 +28,9 @@ imap IMAP custom FETCH with larger literal response (~7KB) +# The quoted string contains {50} which must not be parsed as a literal - imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/ -u user:secret -X 'FETCH 456 BODY[TEXT]' + imap://%HOSTIP:%IMAPPORT/%TESTNUMBER/ -u user:secret -X 'FETCH 456 ("fake {50}" BODY[TEXT])' @@ -39,7 +40,7 @@ IMAP custom FETCH with larger literal response (~7KB) A001 CAPABILITY A002 LOGIN user secret A003 SELECT %TESTNUMBER -A004 FETCH 456 BODY[TEXT] +A004 FETCH 456 ("fake {50}" BODY[TEXT]) A005 LOGOUT