int rfc822_parse_phrase(struct rfc822_parser_context *ctx, string_t *str) { int ret; /* phrase = 1*word / obs-phrase word = atom / quoted-string obs-phrase = word *(word / "." / CFWS) */ if (ctx->data == ctx->end) return 0; if (*ctx->data == '.') return -1; for (;;) { if (*ctx->data == '"') ret = rfc822_parse_quoted_string(ctx, str); else ret = rfc822_parse_atom_or_dot(ctx, str); if (ret <= 0) return ret; if (!IS_ATEXT(*ctx->data) && *ctx->data != '"' && *ctx->data != '.') break; str_append_c(str, ' '); } return rfc822_skip_lwsp(ctx); }
static void test_rfc822_parse_quoted_string(void) { static const struct { const char *input, *output; int ret; } tests[] = { { "\"", "", -1 }, { "\"\"", "", 0 }, { "\"foo\"", "foo", 0 }, { "\"\"foo", "", 1 }, { "\"\"\"", "", 1 }, { "\"\\\"\"", "\"", 0 }, { "\"\\\\\"", "\\", 0 }, { "\"\\\\foo\\\\foo\\\\\"", "\\foo\\foo\\", 0 } }; struct rfc822_parser_context parser; string_t *str = t_str_new(64); unsigned int i = 0; test_begin("rfc822 parse quoted string"); for (i = 0; i < N_ELEMENTS(tests); i++) { rfc822_parser_init(&parser, (const void *)tests[i].input, strlen(tests[i].input), NULL); test_assert_idx(rfc822_parse_quoted_string(&parser, str) == tests[i].ret, i); test_assert_idx(tests[i].ret < 0 || strcmp(tests[i].output, str_c(str)) == 0, i); str_truncate(str, 0); } test_end(); }
int rfc822_parse_content_param(struct rfc822_parser_context *ctx, const char **key_r, const char **value_r) { string_t *tmp; size_t value_pos; int ret; /* .. := *(";" parameter) parameter := attribute "=" value attribute := token value := token / quoted-string */ *key_r = NULL; *value_r = NULL; if (ctx->data == ctx->end) return 0; if (*ctx->data != ';') return -1; ctx->data++; if (rfc822_skip_lwsp(ctx) <= 0) return -1; tmp = t_str_new(64); if (rfc822_parse_mime_token(ctx, tmp) <= 0) return -1; str_append_c(tmp, '\0'); value_pos = str_len(tmp); if (*ctx->data != '=') return -1; ctx->data++; if ((ret = rfc822_skip_lwsp(ctx)) <= 0) { /* broken / no value */ } else if (*ctx->data == '"') { ret = rfc822_parse_quoted_string(ctx, tmp); (void)str_unescape(str_c_modifiable(tmp) + value_pos); } else if (ctx->data != ctx->end && *ctx->data == '=') { /* workaround for broken input: name==?utf-8?b?...?= */ while (ctx->data != ctx->end && *ctx->data != ';' && *ctx->data != ' ' && *ctx->data != '\t' && *ctx->data != '\r' && *ctx->data != '\n') { str_append_c(tmp, *ctx->data); ctx->data++; } } else { ret = rfc822_parse_mime_token(ctx, tmp); } *key_r = str_c(tmp); *value_r = *key_r + value_pos; return ret < 0 ? -1 : 1; }