Lines Matching refs:parser

7 #include "imap-parser.h"
51 size_t cur_pos; /* parser position in input buffer */
74 struct imap_parser *parser;
76 parser = i_new(struct imap_parser, 1);
77 parser->refcount = 1;
78 parser->pool = pool_alloconly_create(MEMPOOL_GROWING"IMAP parser",
80 parser->input = input;
81 parser->output = output;
82 parser->max_line_size = max_line_size;
84 p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT);
85 parser->cur_list = &parser->root_list;
86 return parser;
89 void imap_parser_ref(struct imap_parser *parser)
91 i_assert(parser->refcount > 0);
93 parser->refcount++;
98 struct imap_parser *parser = *_parser;
102 i_assert(parser->refcount > 0);
103 if (--parser->refcount > 0)
106 pool_unref(&parser->pool);
107 i_free(parser);
110 void imap_parser_enable_literal_minus(struct imap_parser *parser)
112 parser->literal_minus = TRUE;
115 void imap_parser_reset(struct imap_parser *parser)
117 p_clear(parser->pool);
119 parser->line_size = 0;
121 p_array_init(&parser->root_list, parser->pool, LIST_INIT_COUNT);
122 parser->cur_list = &parser->root_list;
123 parser->list_arg = NULL;
125 parser->cur_type = ARG_PARSE_NONE;
126 parser->cur_pos = 0;
127 parser->cur_resp_text = FALSE;
129 parser->str_first_escape = 0;
130 parser->literal_size = 0;
132 parser->error = IMAP_PARSE_ERROR_NONE;
133 parser->error_msg = NULL;
135 parser->literal_skip_crlf = FALSE;
136 parser->eol = FALSE;
137 parser->args_added_extra_eol = FALSE;
138 parser->literal_size_return = FALSE;
141 void imap_parser_set_streams(struct imap_parser *parser, struct istream *input,
144 parser->input = input;
145 parser->output = output;
148 const char *imap_parser_get_error(struct imap_parser *parser,
152 *error_r = parser->error;
153 return parser->error_msg;
157 static bool imap_parser_skip_to_next(struct imap_parser *parser,
163 for (i = parser->cur_pos; i < *data_size; i++) {
168 parser->line_size += i;
169 i_stream_skip(parser->input, i);
170 parser->cur_pos = 0;
177 static struct imap_arg *imap_arg_create(struct imap_parser *parser)
181 arg = array_append_space(parser->cur_list);
182 arg->parent = parser->list_arg;
186 static void imap_parser_open_list(struct imap_parser *parser)
188 parser->list_arg = imap_arg_create(parser);
189 parser->list_arg->type = IMAP_ARG_LIST;
190 p_array_init(&parser->list_arg->_data.list, parser->pool,
192 parser->cur_list = &parser->list_arg->_data.list;
194 parser->cur_type = ARG_PARSE_NONE;
197 static bool imap_parser_close_list(struct imap_parser *parser)
201 if (parser->list_arg == NULL) {
203 if ((parser->flags & IMAP_PARSE_FLAG_INSIDE_LIST) != 0) {
204 parser->eol = TRUE;
205 parser->cur_type = ARG_PARSE_NONE;
208 parser->error_msg = "Unexpected ')'";
209 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
213 arg = imap_arg_create(parser);
216 parser->list_arg = parser->list_arg->parent;
217 if (parser->list_arg == NULL) {
218 parser->cur_list = &parser->root_list;
220 parser->cur_list = &parser->list_arg->_data.list;
223 parser->cur_type = ARG_PARSE_NONE;
228 imap_parser_strdup(struct imap_parser *parser,
233 ret = p_malloc(parser->pool, len + 1);
238 static void imap_parser_save_arg(struct imap_parser *parser,
244 arg = imap_arg_create(parser);
246 switch (parser->cur_type) {
258 arg->_data.str = imap_parser_strdup(parser, data, size);
266 str = p_strndup(parser->pool, data+1, size-1);
269 if (parser->str_first_escape >= 0 &&
270 (parser->flags & IMAP_PARSE_FLAG_NO_UNESCAPE) == 0) {
272 (void)str_unescape(str + parser->str_first_escape-1);
278 if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) != 0) {
280 arg->type = parser->literal_nonsync ?
283 arg->_data.literal_size = parser->literal_size;
284 arg->literal8 = parser->literal8;
289 if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_TYPE) != 0)
293 arg->_data.str = imap_parser_strdup(parser, data, size);
294 arg->literal8 = parser->literal8;
301 parser->cur_type = ARG_PARSE_NONE;
304 static bool is_valid_atom_char(struct imap_parser *parser, char chr)
315 if ((parser->flags & IMAP_PARSE_FLAG_ATOM_ALLCHARS) != 0)
317 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
318 parser->error_msg = error_msg;
322 static bool imap_parser_read_atom(struct imap_parser *parser,
328 for (i = parser->cur_pos; i < data_size; i++) {
330 imap_parser_save_arg(parser, data, i);
333 if (parser->list_arg != NULL ||
334 (parser->flags & IMAP_PARSE_FLAG_INSIDE_LIST) != 0) {
335 imap_parser_save_arg(parser, data, i);
337 } else if ((parser->flags &
339 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
340 parser->error_msg = "Unexpected ')'";
344 } else if (!is_valid_atom_char(parser, data[i]))
348 parser->cur_pos = i;
349 return parser->cur_type == ARG_PARSE_NONE;
352 static bool imap_parser_read_string(struct imap_parser *parser,
358 for (i = parser->cur_pos; i < data_size; i++) {
360 imap_parser_save_arg(parser, data, i);
374 if (parser->str_first_escape < 0)
375 parser->str_first_escape = i;
385 (parser->flags & IMAP_PARSE_FLAG_MULTILINE_STR) == 0) {
386 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
387 parser->error_msg = "Missing '\"'";
392 parser->cur_pos = i;
393 return parser->cur_type == ARG_PARSE_NONE;
396 static bool imap_parser_literal_end(struct imap_parser *parser)
398 if (parser->literal_minus && parser->literal_nonsync &&
399 parser->literal_size > 4096) {
400 parser->error_msg = "Non-synchronizing literal size too large";
401 parser->error = IMAP_PARSE_ERROR_LITERAL_TOO_BIG;
405 if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0) {
406 if (parser->line_size >= parser->max_line_size ||
407 parser->literal_size >
408 parser->max_line_size - parser->line_size) {
410 parser->error = IMAP_PARSE_ERROR_LITERAL_TOO_BIG;
411 parser->error_msg = "Literal size too large";
415 if (parser->output != NULL && !parser->literal_nonsync) {
416 o_stream_nsend(parser->output, "+ OK\r\n", 6);
417 if (o_stream_is_corked(parser->output)) {
420 o_stream_uncork(parser->output);
421 o_stream_cork(parser->output);
426 parser->cur_type = ARG_PARSE_LITERAL_DATA;
427 parser->literal_skip_crlf = TRUE;
429 parser->cur_pos = 0;
433 static bool imap_parser_read_literal(struct imap_parser *parser,
440 for (i = parser->cur_pos; i < data_size; i++) {
442 parser->line_size += i+1;
443 i_stream_skip(parser->input, i+1);
444 return imap_parser_literal_end(parser);
447 if (parser->literal_nonsync) {
448 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
449 parser->error_msg = "Expecting '}' after '+'";
454 parser->literal_nonsync = TRUE;
459 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
460 parser->error_msg = "Invalid literal size";
464 prev_size = parser->literal_size;
465 parser->literal_size = parser->literal_size*10 + (data[i]-'0');
467 if (parser->literal_size < prev_size) {
469 parser->error = IMAP_PARSE_ERROR_LITERAL_TOO_BIG;
470 parser->error_msg = "Literal size too large";
475 parser->cur_pos = i;
479 static bool imap_parser_read_literal_data(struct imap_parser *parser,
483 if (parser->literal_skip_crlf) {
489 parser->line_size++;
491 i_stream_skip(parser->input, 1);
498 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
499 parser->error_msg = "Missing LF after literal size";
503 parser->line_size++;
505 i_stream_skip(parser->input, 1);
507 parser->literal_skip_crlf = FALSE;
509 i_assert(parser->cur_pos == 0);
512 if ((parser->flags & IMAP_PARSE_FLAG_LITERAL_SIZE) == 0 ||
513 parser->cur_type == ARG_PARSE_LITERAL_DATA_FORCED) {
515 if (data_size < parser->literal_size)
518 imap_parser_save_arg(parser, data,
519 (size_t)parser->literal_size);
520 parser->cur_pos = (size_t)parser->literal_size;
525 parser->literal_size_return = TRUE;
526 imap_parser_save_arg(parser, uchar_empty_ptr, 0);
531 static bool imap_parser_is_next_resp_text(struct imap_parser *parser)
535 if (parser->cur_list != &parser->root_list ||
536 array_count(parser->cur_list) != 1)
539 arg = array_idx(&parser->root_list, 0);
549 static bool imap_parser_is_next_text(struct imap_parser *parser)
554 if (parser->cur_list != &parser->root_list)
557 arg = array_idx(&parser->root_list, array_count(&parser->root_list)-1);
565 static bool imap_parser_read_text(struct imap_parser *parser,
571 for (i = parser->cur_pos; i < data_size; i++) {
573 imap_parser_save_arg(parser, data, i);
577 parser->cur_pos = i;
578 return parser->cur_type == ARG_PARSE_NONE;
583 static bool imap_parser_read_arg(struct imap_parser *parser)
588 data = i_stream_get_data(parser->input, &data_size);
592 while (parser->cur_type == ARG_PARSE_NONE) {
594 if (!imap_parser_skip_to_next(parser, &data, &data_size))
596 i_assert(parser->cur_pos == 0);
598 if (parser->cur_resp_text &&
599 imap_parser_is_next_text(parser)) {
601 parser->cur_type = ARG_PARSE_TEXT;
612 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
613 parser->error_msg = "CR sent without LF";
619 if ((parser->flags & IMAP_PARSE_FLAG_INSIDE_LIST) != 0) {
620 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
621 parser->error_msg = "Missing ')'";
624 parser->eol = TRUE;
627 parser->cur_type = ARG_PARSE_STRING;
628 parser->str_first_escape = -1;
637 parser->cur_type = ARG_PARSE_ATOM;
640 if ((parser->flags & IMAP_PARSE_FLAG_LITERAL8) == 0) {
641 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
642 parser->error_msg = "literal8 not allowed here";
645 parser->cur_type = ARG_PARSE_LITERAL8;
646 parser->literal_size = 0;
647 parser->literal_nonsync = FALSE;
648 parser->literal8 = TRUE;
651 parser->cur_type = ARG_PARSE_LITERAL;
652 parser->literal_size = 0;
653 parser->literal_nonsync = FALSE;
654 parser->literal8 = FALSE;
657 imap_parser_open_list(parser);
658 if ((parser->flags & IMAP_PARSE_FLAG_STOP_AT_LIST) != 0) {
659 i_stream_skip(parser->input, 1);
664 if (!imap_parser_close_list(parser))
667 if (parser->list_arg == NULL) {
669 parser->cur_pos++;
674 if (!is_valid_atom_char(parser, data[0]))
676 parser->cur_type = ARG_PARSE_ATOM;
680 parser->cur_pos++;
685 switch (parser->cur_type) {
687 if (!imap_parser_read_atom(parser, data, data_size))
689 if ((parser->flags & IMAP_PARSE_FLAG_SERVER_TEXT) == 0)
692 if (imap_parser_is_next_resp_text(parser)) {
697 parser->cur_resp_text = TRUE;
701 if (!imap_parser_read_string(parser, data, data_size))
705 if (parser->cur_pos == data_size)
707 if (data[parser->cur_pos] != '{') {
708 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
709 parser->error_msg = "Expected '{'";
712 parser->cur_type = ARG_PARSE_LITERAL;
713 parser->cur_pos++;
716 if (!imap_parser_read_literal(parser, data, data_size))
721 data = i_stream_get_data(parser->input, &data_size);
726 if (!imap_parser_read_literal_data(parser, data, data_size))
730 if (!imap_parser_read_text(parser, data, data_size))
737 i_assert(parser->cur_type == ARG_PARSE_NONE);
742 #define IS_UNFINISHED(parser) \
743 ((parser)->cur_type != ARG_PARSE_NONE || \
744 ((parser)->cur_list != &parser->root_list && \
745 ((parser)->flags & IMAP_PARSE_FLAG_STOP_AT_LIST) == 0))
747 static int finish_line(struct imap_parser *parser, unsigned int count,
751 int ret = array_count(&parser->root_list);
753 parser->line_size += parser->cur_pos;
754 i_stream_skip(parser->input, parser->cur_pos);
755 parser->cur_pos = 0;
756 parser->cur_resp_text = FALSE;
758 if (parser->list_arg != NULL && !parser->literal_size_return &&
759 (parser->flags & IMAP_PARSE_FLAG_STOP_AT_LIST) == 0) {
760 parser->error = IMAP_PARSE_ERROR_BAD_SYNTAX;
761 parser->error_msg = "Missing ')'";
766 arg = array_append_space(&parser->root_list);
768 parser->args_added_extra_eol = TRUE;
770 *args_r = array_get(&parser->root_list, &count);
774 int imap_parser_read_args(struct imap_parser *parser, unsigned int count,
778 parser->flags = flags;
780 if (parser->args_added_extra_eol) {
782 array_delete(&parser->root_list,
783 array_count(&parser->root_list)-1, 1);
784 parser->args_added_extra_eol = FALSE;
785 parser->literal_size_return = FALSE;
788 while (!parser->eol && (count == 0 || IS_UNFINISHED(parser) ||
789 array_count(&parser->root_list) < count)) {
790 if (!imap_parser_read_arg(parser))
793 if (parser->line_size > parser->max_line_size) {
794 parser->error = IMAP_PARSE_ERROR_LINE_TOO_LONG;
795 parser->error_msg = "IMAP command line too large";
800 if (parser->error != IMAP_PARSE_ERROR_NONE) {
802 parser->line_size += parser->cur_pos;
803 i_stream_skip(parser->input, parser->cur_pos);
804 parser->cur_pos = 0;
807 } else if ((!IS_UNFINISHED(parser) && count > 0 &&
808 array_count(&parser->root_list) >= count) ||
809 parser->eol || parser->literal_size_return) {
811 return finish_line(parser, count, args_r);
820 imap_parser_get_last_literal_size(struct imap_parser *parser,
827 list = &parser->root_list;
828 args = array_get_modifiable(&parser->root_list, &count);
848 bool imap_parser_get_literal_size(struct imap_parser *parser, uoff_t *size_r)
853 last_arg = imap_parser_get_last_literal_size(parser, &list);
860 void imap_parser_read_last_literal(struct imap_parser *parser)
865 i_assert(parser->literal_size_return);
867 last_arg = imap_parser_get_last_literal_size(parser, &list);
870 parser->cur_type = ARG_PARSE_LITERAL_DATA_FORCED;
871 i_assert(parser->literal_size == last_arg->_data.literal_size);
874 array_delete(&parser->root_list, array_count(&parser->root_list)-1, 1);
875 parser->args_added_extra_eol = FALSE;
879 parser->literal_size_return = FALSE;
882 int imap_parser_finish_line(struct imap_parser *parser, unsigned int count,
890 ret = imap_parser_read_args(parser, count, flags, args_r);
895 if (parser->cur_type == ARG_PARSE_ATOM) {
896 data = i_stream_get_data(parser->input, &data_size);
897 imap_parser_save_arg(parser, data, data_size);
900 return finish_line(parser, count, args_r);
903 const char *imap_parser_read_word(struct imap_parser *parser)
908 data = i_stream_get_data(parser->input, &data_size);
917 parser->line_size += data_size;
918 i_stream_skip(parser->input, data_size);
919 return p_strndup(parser->pool, data, i);