static void test_message_header_parser_partial(void) { struct message_header_parser_ctx *parser; struct message_header_line *hdr; struct istream *input; unsigned int i, max = (strlen(test1_msg)-TEST1_MSG_BODY_LEN)*2; string_t *str; int ret; test_begin("message header parser partial"); input = test_istream_create(test1_msg); test_istream_set_allow_eof(input, FALSE); str = t_str_new(max); parser = message_parse_header_init(input, NULL, 0); for (i = 0; i <= max; i++) { test_istream_set_size(input, i/2); while ((ret = message_parse_header_next(parser, &hdr)) > 0) hdr_write(str, hdr); test_assert((ret == 0 && i < max) || (ret < 0 && i == max)); } message_parse_header_deinit(&parser); str_append(str, " body"); test_assert(strcmp(str_c(str), test1_msg) == 0); i_stream_unref(&input); test_end(); }
static void test_message_header_parser(void) { static enum message_header_parser_flags max_hdr_flags = MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP | MESSAGE_HEADER_PARSER_FLAG_DROP_CR | MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE; enum message_header_parser_flags hdr_flags; struct message_header_parser_ctx *parser; struct message_size hdr_size; struct istream *input; test_begin("message header parser"); input = test_istream_create(test1_msg); for (hdr_flags = 0; hdr_flags <= max_hdr_flags; hdr_flags++) { i_stream_seek(input, 0); parser = message_parse_header_init(input, &hdr_size, hdr_flags); test_message_header_parser_one(parser, hdr_flags); message_parse_header_deinit(&parser); } test_assert(hdr_size.physical_size == strlen(test1_msg)-TEST1_MSG_BODY_LEN); test_assert(hdr_size.virtual_size == strlen(test1_msg) - TEST1_MSG_BODY_LEN + 4); i_stream_unref(&input); test_end(); }
static int parse_next_header_init(struct message_parser_ctx *ctx, struct message_block *block_r) { i_assert(ctx->hdr_parser_ctx == NULL); ctx->hdr_parser_ctx = message_parse_header_init(ctx->input, &ctx->part->header_size, ctx->hdr_flags); ctx->part_seen_content_type = FALSE; ctx->parse_next_block = parse_next_header; return parse_next_header(ctx, block_r); }
void message_parse_header(struct istream *input, struct message_size *hdr_size, enum message_header_parser_flags flags, message_header_callback_t *callback, void *context) { struct message_header_parser_ctx *hdr_ctx; struct message_header_line *hdr; int ret; hdr_ctx = message_parse_header_init(input, hdr_size, flags); while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) callback(hdr, context); i_assert(ret != 0); message_parse_header_deinit(&hdr_ctx); /* call after the final skipping */ callback(NULL, context); }
static void test_message_header_parser_no_eoh(void) { static const char *str = "a:b\n"; struct message_header_parser_ctx *parser; struct message_header_line *hdr; struct istream *input; test_begin("message header parser no EOH"); input = test_istream_create(str); parser = message_parse_header_init(input, NULL, 0); test_assert(message_parse_header_next(parser, &hdr) > 0 && strcmp(hdr->name, "a") == 0); test_assert(message_parse_header_next(parser, &hdr) < 0); message_parse_header_deinit(&parser); test_assert(input->stream_errno == 0); i_stream_unref(&input); test_end(); }
static void test_message_header_parser_long_lines_str(const char *str, unsigned int buffer_size, struct message_size *size_r) { struct message_header_parser_ctx *parser; struct message_header_line *hdr; struct istream *input; unsigned int i, len = strlen(str); input = test_istream_create(str); test_istream_set_max_buffer_size(input, buffer_size); parser = message_parse_header_init(input, size_r, 0); for (i = 1; i <= len; i++) { test_istream_set_size(input, i); while (message_parse_header_next(parser, &hdr) > 0) ; } message_parse_header_deinit(&parser); i_stream_unref(&input); }
bool mbox_sync_parse_match_mail(struct mbox_mailbox *mbox, struct mail_index_view *view, uint32_t seq) { struct mbox_sync_mail_context ctx; struct message_header_parser_ctx *hdr_ctx; struct message_header_line *hdr; struct header_func *func; struct mbox_md5_context *mbox_md5_ctx; const void *data; bool expunged; uint32_t uid; int ret; /* we only wish to be sure that this mail actually is what we expect it to be. If there's X-UID header and it matches our UID, we use it. Otherwise it could mean that the X-UID header is invalid and it's just not yet been rewritten. In that case use MD5 sum, if it exists. */ mail_index_lookup_uid(view, seq, &uid); memset(&ctx, 0, sizeof(ctx)); mbox_md5_ctx = mbox->md5_v.init(); hdr_ctx = message_parse_header_init(mbox->mbox_stream, NULL, 0); while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) { if (hdr->eoh) break; func = bsearch(hdr->name, header_funcs, N_ELEMENTS(header_funcs), sizeof(*header_funcs), mbox_sync_bsearch_header_func_cmp); if (func != NULL) { if (strcasecmp(hdr->name, "X-UID") == 0) { if (hdr->continues) { hdr->use_full_value = TRUE; continue; } (void)parse_x_uid(&ctx, hdr); if (ctx.mail.uid == uid) break; } } else { mbox->md5_v.more(mbox_md5_ctx, hdr); } } i_assert(ret != 0); message_parse_header_deinit(&hdr_ctx); mbox->md5_v.finish(mbox_md5_ctx, ctx.hdr_md5_sum); if (ctx.mail.uid == uid) return TRUE; /* match by MD5 sum */ mbox->mbox_save_md5 = TRUE; mail_index_lookup_ext(view, seq, mbox->md5hdr_ext_idx, &data, &expunged); return data == NULL ? 0 : memcmp(data, ctx.hdr_md5_sum, 16) == 0; }
int mbox_sync_parse_next_mail(struct istream *input, struct mbox_sync_mail_context *ctx) { struct mbox_sync_context *sync_ctx = ctx->sync_ctx; struct message_header_parser_ctx *hdr_ctx; struct message_header_line *hdr; struct mbox_sync_header_func *func; struct mbox_md5_context *mbox_md5_ctx; size_t line_start_pos; int i, ret; ctx->hdr_offset = ctx->mail.offset; ctx->mail.flags = MAIL_RECENT; /* default to having recent flag */ ctx->header_first_change = (size_t)-1; ctx->header_last_change = 0; for (i = 0; i < MBOX_HDR_COUNT; i++) ctx->hdr_pos[i] = (size_t)-1; ctx->content_length = (uoff_t)-1; str_truncate(ctx->header, 0); mbox_md5_ctx = ctx->sync_ctx->mbox->md5_v.init(); line_start_pos = 0; hdr_ctx = message_parse_header_init(input, NULL, 0); while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0) { if (hdr->eoh) { ctx->have_eoh = TRUE; break; } if (!hdr->continued) { line_start_pos = str_len(ctx->header); str_append(ctx->header, hdr->name); str_append_n(ctx->header, hdr->middle, hdr->middle_len); } func = bsearch(hdr->name, header_funcs, N_ELEMENTS(header_funcs), sizeof(*header_funcs), mbox_sync_bsearch_header_func_cmp); if (func != NULL) { if (hdr->continues) { hdr->use_full_value = TRUE; continue; } if (!func->func(ctx, hdr)) { /* this header is broken, remove it */ ctx->need_rewrite = TRUE; str_truncate(ctx->header, line_start_pos); if (ctx->header_first_change == (size_t)-1) { ctx->header_first_change = line_start_pos; } continue; } buffer_append(ctx->header, hdr->full_value, hdr->full_value_len); } else { ctx->sync_ctx->mbox->md5_v.more(mbox_md5_ctx, hdr); buffer_append(ctx->header, hdr->value, hdr->value_len); } if (!hdr->no_newline) { if (hdr->crlf_newline) str_append_c(ctx->header, '\r'); str_append_c(ctx->header, '\n'); } } i_assert(ret != 0); message_parse_header_deinit(&hdr_ctx); ctx->sync_ctx->mbox->md5_v.finish(mbox_md5_ctx, ctx->hdr_md5_sum); if ((ctx->seq == 1 && !ctx->seen_imapbase) || (ctx->seq > 1 && sync_ctx->dest_first_mail)) { /* missing X-IMAPbase */ ctx->need_rewrite = TRUE; if (sync_ctx->base_uid_validity == 0) { /* figure out a new UIDVALIDITY for us. */ sync_ctx->base_uid_validity = sync_ctx->hdr->uid_validity != 0 && !sync_ctx->renumber_uids ? sync_ctx->hdr->uid_validity : I_MAX((uint32_t)ioloop_time, 1); } } ctx->body_offset = input->v_offset; if (input->stream_errno != 0) { mbox_sync_set_critical(ctx->sync_ctx, "read(%s) failed: %s", i_stream_get_name(input), i_stream_get_error(input)); return -1; } return 0; }