static int imap_parser_read_atom(struct imap_parser *parser, const unsigned char *data, size_t data_size) { size_t i; /* read until we've found space, CR or LF. */ for (i = parser->cur_pos; i < data_size; i++) { if (data[i] == ' ' || is_linebreak(data[i])) { imap_parser_save_arg(parser, data, i); break; } else if (data[i] == ')') { if (parser->list_arg != NULL || (parser->flags & IMAP_PARSE_FLAG_INSIDE_LIST) != 0) { imap_parser_save_arg(parser, data, i); break; } else if ((parser->flags & IMAP_PARSE_FLAG_ATOM_ALLCHARS) == 0) { parser->error = "Unexpected ')'"; return FALSE; } /* assume it's part of the atom */ } else if (!is_valid_atom_char(parser, data[i])) return FALSE; } parser->cur_pos = i; return parser->cur_type == ARG_PARSE_NONE; }
static int managesieve_parser_read_atom(struct managesieve_parser *parser, const unsigned char *data, size_t data_size) { size_t i; /* read until we've found space, CR or LF. */ for (i = parser->cur_pos; i < data_size; i++) { if (data[i] == ' ' || data[i] == ')' || is_linebreak(data[i])) { managesieve_parser_save_arg(parser, data, i); break; } else if (!is_valid_atom_char(parser, data[i])) return FALSE; } parser->cur_pos = i; return parser->cur_type == ARG_PARSE_NONE; }
/* Returns TRUE if argument was fully processed. Also returns TRUE if an argument inside a list was processed. */ static int managesieve_parser_read_arg(struct managesieve_parser *parser) { const unsigned char *data; size_t data_size; data = i_stream_get_data(parser->input, &data_size); if (data_size == 0) return FALSE; while (parser->cur_type == ARG_PARSE_NONE) { /* we haven't started parsing yet */ if (!managesieve_parser_skip_to_next(parser, &data, &data_size)) return FALSE; i_assert(parser->cur_pos == 0); switch (data[0]) { case '\r': case '\n': /* unexpected end of line */ parser->eol = TRUE; return FALSE; case '"': parser->cur_type = ARG_PARSE_STRING; parser->str_first_escape = -1; break; case '{': parser->cur_type = ARG_PARSE_LITERAL; parser->literal_size = 0; parser->literal_nonsync = FALSE; break; default: if (!is_valid_atom_char(parser, data[0])) return FALSE; parser->cur_type = ARG_PARSE_ATOM; break; } parser->cur_pos++; } i_assert(data_size > 0); switch (parser->cur_type) { case ARG_PARSE_ATOM: if (!managesieve_parser_read_atom(parser, data, data_size)) return FALSE; break; case ARG_PARSE_STRING: if ((parser->flags & MANAGESIEVE_PARSE_FLAG_STRING_STREAM) != 0) { parser->eol = TRUE; parser->line_size += parser->cur_pos; i_stream_skip(parser->input, parser->cur_pos); parser->cur_pos = 0; parser->str_stream = quoted_string_istream_create(parser); managesieve_parser_save_arg(parser, NULL, 0); } else if (!managesieve_parser_read_string(parser, data, data_size)) { return FALSE; } break; case ARG_PARSE_LITERAL: if (!managesieve_parser_read_literal(parser, data, data_size)) return FALSE; /* pass through to parsing data. since input->skip was modified, we need to get the data start position again. */ data = i_stream_get_data(parser->input, &data_size); /* fall through */ case ARG_PARSE_LITERAL_DATA: if (!managesieve_parser_read_literal_data(parser, data, data_size)) return FALSE; break; default: i_unreached(); } i_assert(parser->cur_type == ARG_PARSE_NONE); return TRUE; }
/* Returns TRUE if argument was fully processed. Also returns TRUE if an argument inside a list was processed. */ static int imap_parser_read_arg(struct imap_parser *parser) { const unsigned char *data; size_t data_size; data = i_stream_get_data(parser->input, &data_size); if (data_size == 0) return FALSE; while (parser->cur_type == ARG_PARSE_NONE) { /* we haven't started parsing yet */ if (!imap_parser_skip_to_next(parser, &data, &data_size)) return FALSE; i_assert(parser->cur_pos == 0); if (parser->cur_resp_text && imap_parser_is_next_text(parser)) { /* we just parsed [resp-text-code] */ parser->cur_type = ARG_PARSE_TEXT; break; } switch (data[0]) { case '\r': if (data_size == 1) { /* wait for LF */ return FALSE; } if (data[1] != '\n') { parser->error = "CR sent without LF"; return FALSE; } /* fall through */ case '\n': /* unexpected end of line */ if ((parser->flags & IMAP_PARSE_FLAG_INSIDE_LIST) != 0) { parser->error = "Missing ')'"; return FALSE; } parser->eol = TRUE; return FALSE; case '"': parser->cur_type = ARG_PARSE_STRING; parser->str_first_escape = -1; break; case '~': if ((parser->flags & IMAP_PARSE_FLAG_LITERAL8) == 0) { parser->error = "literal8 not allowed here"; return FALSE; } parser->cur_type = ARG_PARSE_LITERAL8; parser->literal_size = 0; parser->literal_nonsync = FALSE; parser->literal8 = TRUE; break; case '{': parser->cur_type = ARG_PARSE_LITERAL; parser->literal_size = 0; parser->literal_nonsync = FALSE; parser->literal8 = FALSE; break; case '(': imap_parser_open_list(parser); if ((parser->flags & IMAP_PARSE_FLAG_STOP_AT_LIST) != 0) { i_stream_skip(parser->input, 1); return FALSE; } break; case ')': if (!imap_parser_close_list(parser)) return FALSE; if (parser->list_arg == NULL) { /* end of argument */ parser->cur_pos++; return TRUE; } break; default: if (!is_valid_atom_char(parser, data[0])) return FALSE; parser->cur_type = ARG_PARSE_ATOM; break; } parser->cur_pos++; } i_assert(data_size > 0); switch (parser->cur_type) { case ARG_PARSE_ATOM: if (!imap_parser_read_atom(parser, data, data_size)) return FALSE; if ((parser->flags & IMAP_PARSE_FLAG_SERVER_TEXT) == 0) break; if (imap_parser_is_next_resp_text(parser)) { /* we just parsed OK/NO/BAD/BYE. after parsing the [resp-text-code] the rest of the message can contain pretty much any random text, which we can't parse as if it was valid IMAP input */ parser->cur_resp_text = TRUE; } break; case ARG_PARSE_STRING: if (!imap_parser_read_string(parser, data, data_size)) return FALSE; break; case ARG_PARSE_LITERAL8: if (parser->cur_pos == data_size) return FALSE; if (data[parser->cur_pos] != '{') { parser->error = "Expected '{'"; return FALSE; } parser->cur_type = ARG_PARSE_LITERAL; parser->cur_pos++; /* fall through */ case ARG_PARSE_LITERAL: if (!imap_parser_read_literal(parser, data, data_size)) return FALSE; /* pass through to parsing data. since input->skip was modified, we need to get the data start position again. */ data = i_stream_get_data(parser->input, &data_size); /* fall through */ case ARG_PARSE_LITERAL_DATA: case ARG_PARSE_LITERAL_DATA_FORCED: if (!imap_parser_read_literal_data(parser, data, data_size)) return FALSE; break; case ARG_PARSE_TEXT: if (!imap_parser_read_text(parser, data, data_size)) return FALSE; break; default: i_unreached(); } i_assert(parser->cur_type == ARG_PARSE_NONE); return TRUE; }