]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
imap: skip literals inside quoted strings
authorcalm329 <calmdev0329@gmail.com>
Wed, 14 Jan 2026 17:12:20 +0000 (09:12 -0800)
committerDaniel Stenberg <daniel@haxx.se>
Thu, 15 Jan 2026 21:38:15 +0000 (22:38 +0100)
Fixes #20320
Closes #20322

lib/imap.c
tests/data/test3206

index 4c9d14232a7b70547df052d4a58a0be947ec069b..4ef055c13db295817b415f81dd4e79e999d25cc7 100644 (file)
@@ -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) &&
index 90c5b02c0b89b0d28362e27925c19291f8d0c79e..8665e6207fc0def8e6e699718a55d4fd09dbe4a8 100644 (file)
@@ -15,7 +15,7 @@ CUSTOMREQUEST
 %repeat[120 x Testing large IMAP literal with custom FETCH. XXXXXXXXXXXXX%0d]%
 </data>
 <datacheck>
-* 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]%
 </datacheck>
 </reply>
@@ -28,8 +28,9 @@ imap
 <name>
 IMAP custom FETCH with larger literal response (~7KB)
 </name>
+# The quoted string contains {50} which must not be parsed as a literal
 <command>
- 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])'
 </command>
 </client>
 
@@ -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
 </protocol>
 </verify>