start = ++ctx->data;
for (; ctx->data < ctx->end; ctx->data++) {
switch (*ctx->data) {
+ case '\0':
+ if (ctx->last_comment != NULL &&
+ ctx->nul_replacement_char != '\0') {
+ str_append_data(ctx->last_comment, start,
+ ctx->data - start);
+ str_append_c(ctx->last_comment,
+ ctx->nul_replacement_char);
+ start = ctx->data + 1;
+ }
+ break;
case '(':
level++;
break;
if (ctx->data >= ctx->end)
return -1;
- if (*ctx->data == '\r' || *ctx->data == '\n') {
- /* quoted-pair doesn't allow CR/LF.
+ if (*ctx->data == '\r' || *ctx->data == '\n' ||
+ *ctx->data == '\0') {
+ /* quoted-pair doesn't allow CR/LF/NUL.
They are part of the obs-qp though, so don't
return them as error. */
ctx->data--;
for (start = ctx->data; ctx->data < ctx->end; ctx->data++) {
switch (*ctx->data) {
+ case '\0':
+ if (ctx->nul_replacement_char != '\0') {
+ str_append_data(str, start, ctx->data - start);
+ str_append_c(str, ctx->nul_replacement_char);
+ start = ctx->data + 1;
+ }
+ break;
case '"':
str_append_data(str, start, ctx->data - start);
ctx->data++;
for (start = ctx->data++; ctx->data < ctx->end; ctx->data++) {
switch (*ctx->data) {
+ case '\0':
+ if (ctx->nul_replacement_char != '\0') {
+ str_append_data(str, start, ctx->data - start);
+ str_append_c(str, ctx->nul_replacement_char);
+ start = ctx->data + 1;
+ }
+ break;
case '[':
/* not allowed */
return -1;
#ifndef RFC822_PARSER_H
#define RFC822_PARSER_H
+/* This can be used as a common NUL replacement character */
+#define RFC822_NUL_REPLACEMENT_CHAR 0x80
+
struct rfc822_parser_context {
const unsigned char *data, *end;
string_t *last_comment;
+
+ /* Replace NULs with this character */
+ char nul_replacement_char;
};
#define IS_ATEXT(c) \
test_end();
}
+static void test_rfc822_parse_comment_nuls(void)
+{
+ const unsigned char input[] = "(\000a\000\000b\\\000c(\000d)\000)";
+ const char output[] = "!a!!b\\!c(!d)!";
+ struct rfc822_parser_context parser;
+ string_t *str = t_str_new(64);
+
+ test_begin("rfc822 parse comment with NULs");
+
+ rfc822_parser_init(&parser, input, sizeof(input)-1, str);
+ test_assert(rfc822_skip_comment(&parser) == 0);
+ /* should be same as input, except the outer () removed */
+ test_assert(str_len(str) == sizeof(input)-1-2 &&
+ memcmp(input+1, str_data(str), str_len(str)) == 0);
+ rfc822_parser_deinit(&parser);
+
+ str_truncate(str, 0);
+ rfc822_parser_init(&parser, input, sizeof(input)-1, str);
+ parser.nul_replacement_char = '!';
+ test_assert(rfc822_skip_comment(&parser) == 0);
+ test_assert(strcmp(str_c(str), output) == 0);
+ rfc822_parser_deinit(&parser);
+
+ test_end();
+}
+
static void test_rfc822_parse_quoted_string(void)
{
static const struct {
{
static void (*const test_functions[])(void) = {
test_rfc822_parse_comment,
+ test_rfc822_parse_comment_nuls,
test_rfc822_parse_quoted_string,
test_rfc822_parse_domain_literal,
test_rfc822_parse_content_param,