]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail: rfc822-parser: Strip away folding whitespace from comments
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Sat, 21 Apr 2018 10:46:21 +0000 (13:46 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 30 Aug 2018 08:13:07 +0000 (11:13 +0300)
src/lib-mail/rfc822-parser.c
src/lib-mail/test-rfc822-parser.c

index 886707549a6dec918bbeb89f0ebc36376ddbb677..789d64be747dc7e1e2fa96ba07e4d66290aaaac6 100644 (file)
@@ -64,6 +64,7 @@ void rfc822_parser_init(struct rfc822_parser_context *ctx,
 int rfc822_skip_comment(struct rfc822_parser_context *ctx)
 {
        const unsigned char *start;
+       size_t len;
        int level = 1;
 
        i_assert(*ctx->data == '(');
@@ -87,16 +88,33 @@ int rfc822_skip_comment(struct rfc822_parser_context *ctx)
                                return ctx->data < ctx->end ? 1 : 0;
                        }
                        break;
-               case '\\':
-                       if (ctx->last_comment != NULL) {
-                               str_append_data(ctx->last_comment, start,
-                                               ctx->data - start);
-                       }
+               case '\n':
+                       /* folding whitespace, remove the (CR)LF */
+                       if (ctx->last_comment == NULL)
+                               break;
+                       len = ctx->data - start;
+                       if (len > 0 && start[len-1] == '\r')
+                               len--;
+                       str_append_data(ctx->last_comment, start, len);
                        start = ctx->data + 1;
-
+                       break;
+               case '\\':
                        ctx->data++;
                        if (ctx->data >= ctx->end)
                                return -1;
+
+                       if (*ctx->data == '\r' || *ctx->data == '\n') {
+                               /* quoted-pair doesn't allow CR/LF.
+                                  They are part of the obs-qp though, so don't
+                                  return them as error. */
+                               ctx->data--;
+                               break;
+                       }
+                       if (ctx->last_comment != NULL) {
+                               str_append_data(ctx->last_comment, start,
+                                               ctx->data - start - 1);
+                       }
+                       start = ctx->data;
                        break;
                }
        }
index 3b0aaae640b5e350d65a2b6876b28a75de5d4fb4..569232afcffe682731b823f0d80cd272397ed7a1 100644 (file)
@@ -5,6 +5,51 @@
 #include "rfc822-parser.h"
 #include "test-common.h"
 
+static void test_rfc822_parse_comment(void)
+{
+       static const struct {
+               const char *input, *output;
+               int ret;
+       } tests[] = {
+               { "(", "", -1 },
+               { "(()", "", -1 },
+
+               { "()", "", 0 },
+               { "(())", "()", 0 },
+               { "(foo ( bar ) baz)", "foo ( bar ) baz", 0 },
+               { "(foo\t\tbar)", "foo\t\tbar", 0 },
+               { "(foo\\(bar)", "foo(bar", 0 },
+               { "(foo\\\\bar)", "foo\\bar", 0 },
+               { "(foo\\\\\\\\)", "foo\\\\", 0 },
+               { "(foo\\)bar)", "foo)bar", 0 },
+               { "(foo\"flop\"\"bar)", "foo\"flop\"\"bar", 0 },
+
+               { "(foo\n bar)", "foo bar", 0 },
+               { "(foo\n\t\t bar)", "foo\t\t bar", 0 },
+               { "(foo\\\n bar)", "foo\\ bar", 0 },
+               { "(foo\\\r\n bar)", "foo\\ bar", 0 },
+       };
+       struct rfc822_parser_context parser, parser2;
+       string_t *str = t_str_new(64);
+       unsigned int i = 0;
+
+       test_begin("rfc822 parse comment");
+       for (i = 0; i < N_ELEMENTS(tests); i++) {
+               rfc822_parser_init(&parser, (const void *)tests[i].input,
+                                  strlen(tests[i].input), str);
+               rfc822_parser_init(&parser2, (const void *)tests[i].input,
+                                  strlen(tests[i].input), NULL);
+               test_assert_idx(rfc822_skip_comment(&parser) == tests[i].ret, i);
+               test_assert_idx(rfc822_skip_comment(&parser2) == tests[i].ret, i);
+               test_assert_idx(tests[i].ret < 0 ||
+                               strcmp(tests[i].output, str_c(str)) == 0, i);
+               rfc822_parser_deinit(&parser);
+               rfc822_parser_deinit(&parser2);
+               str_truncate(str, 0);
+       }
+       test_end();
+}
+
 static void test_rfc822_parse_quoted_string(void)
 {
        static const struct {
@@ -108,6 +153,7 @@ static void test_rfc822_parse_content_param(void)
 int main(void)
 {
        static void (*const test_functions[])(void) = {
+               test_rfc822_parse_comment,
                test_rfc822_parse_quoted_string,
                test_rfc822_parse_domain_literal,
                test_rfc822_parse_content_param,