static int parse_next_body_to_eof(struct message_parser_ctx *ctx, struct message_block *block_r) { bool full; int ret; if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) return ret; parse_body_add_block(ctx, block_r); return 1; }
static int parse_part_finish(struct message_parser_ctx *ctx, struct message_boundary *boundary, struct message_block *block_r, bool first_line) { struct message_part *part; size_t line_size; i_assert(ctx->last_boundary == NULL); /* get back to parent MIME part, summing the child MIME part sizes into parent's body sizes */ for (part = ctx->part; part != boundary->part; part = part->parent) { message_size_add(&part->parent->body_size, &part->body_size); message_size_add(&part->parent->body_size, &part->header_size); } i_assert(part != NULL); ctx->part = part; if (boundary->epilogue_found) { /* this boundary isn't needed anymore */ ctx->boundaries = boundary->next; } else { /* forget about the boundaries we possibly skipped */ ctx->boundaries = boundary; } /* the boundary itself should already be in buffer. add that. */ block_r->data = i_stream_get_data(ctx->input, &block_r->size); i_assert(block_r->size >= ctx->skip); block_r->data += ctx->skip; /* [[\r]\n]--<boundary>[--] */ if (first_line) line_size = 0; else if (block_r->data[0] == '\r') { i_assert(block_r->data[1] == '\n'); line_size = 2; } else { i_assert(block_r->data[0] == '\n'); line_size = 1; } line_size += 2 + boundary->len + (boundary->epilogue_found ? 2 : 0); i_assert(block_r->size >= ctx->skip + line_size); block_r->size = line_size; parse_body_add_block(ctx, block_r); ctx->parse_next_block = parse_next_body_skip_boundary_line; if ((ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0) return 1; return ctx->parse_next_block(ctx, block_r); }
static int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx, struct message_block *block_r) { const unsigned char *ptr; int ret; bool full; if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) return ret; ptr = memchr(block_r->data, '\n', block_r->size); if (ptr == NULL) { parse_body_add_block(ctx, block_r); if (block_r->size > 0 && (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0) return 1; return 0; } /* found the LF */ block_r->size = (ptr - block_r->data) + 1; parse_body_add_block(ctx, block_r); if (ctx->boundaries == NULL || ctx->boundaries->part != ctx->part) { /* epilogue */ if (ctx->boundaries != NULL) ctx->parse_next_block = parse_next_body_to_boundary; else ctx->parse_next_block = parse_next_body_to_eof; } else { /* a new MIME part begins */ ctx->parse_next_block = parse_next_mime_header_init; } if (block_r->size > 0 && (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_BOUNDARIES) != 0) return 1; return ctx->parse_next_block(ctx, block_r); }
static int parse_next_body_skip_boundary_line(struct message_parser_ctx *ctx, struct message_block *block_r) { const unsigned char *ptr; int ret; bool full; if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) return ret; ptr = memchr(block_r->data, '\n', block_r->size); if (ptr == NULL) { parse_body_add_block(ctx, block_r); return 1; } /* found the LF */ block_r->size = (ptr - block_r->data) + 1; parse_body_add_block(ctx, block_r); /* a new MIME part begins */ ctx->parse_next_block = parse_next_mime_header_init; return 1; }
static int parse_next_body_to_eof(struct message_parser_ctx *ctx, struct message_block *block_r) { bool full; int ret; if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) return ret; parse_body_add_block(ctx, block_r); if ((ctx->part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0 && (ctx->flags & MESSAGE_PARSER_FLAG_INCLUDE_MULTIPART_BLOCKS) == 0) return 0; return 1; }
static int parse_part_finish(struct message_parser_ctx *ctx, struct message_boundary *boundary, struct message_block *block_r, bool first_line) { struct message_part *part; /* get back to parent MIME part, summing the child MIME part sizes into parent's body sizes */ for (part = ctx->part; part != boundary->part; part = part->parent) { message_size_add(&part->parent->body_size, &part->body_size); message_size_add(&part->parent->body_size, &part->header_size); } ctx->part = part; if (boundary->epilogue_found) { /* this boundary isn't needed anymore */ ctx->boundaries = boundary->next; if (ctx->boundaries != NULL) ctx->parse_next_block = parse_next_body_to_boundary; else ctx->parse_next_block = parse_next_body_to_eof; return ctx->parse_next_block(ctx, block_r); } /* forget about the boundaries we possibly skipped */ ctx->boundaries = boundary; /* the boundary itself should already be in buffer. add that. */ block_r->data = i_stream_get_data(ctx->input, &block_r->size); i_assert(block_r->size >= ctx->skip + 2 + boundary->len + (first_line ? 0 : 1)); block_r->data += ctx->skip; /* [\n]--<boundary> */ block_r->size = (first_line ? 0 : 1) + 2 + boundary->len; parse_body_add_block(ctx, block_r); ctx->parse_next_block = parse_next_body_skip_boundary_line; return 1; }
static int parse_next_body_to_boundary(struct message_parser_ctx *ctx, struct message_block *block_r) { struct message_boundary *boundary = NULL; const unsigned char *data, *cur, *next, *end; size_t boundary_start; int ret; bool full; if ((ret = message_parser_read_more(ctx, block_r, &full)) <= 0) return ret; data = block_r->data; if (ctx->last_chr == '\n') { /* handle boundary in first line of message. alternatively it's an empty line. */ ret = boundary_line_find(ctx, block_r->data, block_r->size, full, &boundary); if (ret >= 0) { return ret == 0 ? 0 : parse_part_finish(ctx, boundary, block_r, TRUE); } } i_assert(block_r->size > 0); boundary_start = 0; /* skip to beginning of the next line. the first line was handled already. */ cur = data; end = data + block_r->size; while ((next = memchr(cur, '\n', end - cur)) != NULL) { cur = next + 1; boundary_start = next - data; if (next > data && next[-1] == '\r') boundary_start--; if (boundary_start != 0) { /* we can at least skip data until the first [CR]LF. input buffer can't be full anymore. */ full = FALSE; } ret = boundary_line_find(ctx, cur, end - cur, full, &boundary); if (ret >= 0) { /* found / need more data */ if (ret == 0 && boundary_start == 0) ctx->want_count += cur - block_r->data; break; } } if (next != NULL) { /* found / need more data */ i_assert(ret >= 0); i_assert(!(ret == 0 && full)); } else if (boundary_start == 0) { /* no linefeeds in this block. we can just skip it. */ ret = 0; boundary_start = block_r->size; } else { /* the boundary wasn't found from this data block, we'll need more data. */ ret = 0; ctx->want_count = (block_r->size - boundary_start) + 1; } if (ret > 0 || (ret == 0 && !ctx->eof)) { /* a) we found the boundary b) we need more data and haven't reached EOF yet so leave CR+LF + last line to buffer */ block_r->size = boundary_start; } if (block_r->size != 0) { parse_body_add_block(ctx, block_r); return 1; } return ret <= 0 ? ret : parse_part_finish(ctx, boundary, block_r, FALSE); }