static int message_search_msg_real(struct message_search_context *ctx, struct istream *input, struct message_part *parts, const char **error_r) { const enum message_header_parser_flags hdr_parser_flags = MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE; struct message_parser_ctx *parser_ctx; struct message_block raw_block; struct message_part *new_parts; int ret; message_search_reset(ctx); if (parts != NULL) { parser_ctx = message_parser_init_from_parts(parts, input, hdr_parser_flags, 0); } else { parser_ctx = message_parser_init(pool_datastack_create(), input, hdr_parser_flags, 0); } while ((ret = message_parser_parse_next_block(parser_ctx, &raw_block)) > 0) { if (message_search_more(ctx, &raw_block)) { ret = 1; break; } } i_assert(ret != 0); if (ret < 0 && input->stream_errno == 0) { /* normal exit */ ret = 0; } if (message_parser_deinit_from_parts(&parser_ctx, &new_parts, error_r) < 0) { /* broken parts */ ret = -1; } return ret; }
static void search_header_arg(struct mail_search_arg *arg, struct search_header_context *ctx) { struct message_search_context *msg_search_ctx; struct message_block block; struct message_header_line hdr; int ret; /* first check that the field name matches to argument. */ switch (arg->type) { case SEARCH_BEFORE: case SEARCH_ON: case SEARCH_SINCE: if (arg->value.date_type != MAIL_SEARCH_DATE_TYPE_SENT) return; /* date is handled differently than others */ if (strcasecmp(ctx->hdr->name, "Date") == 0) { if (ctx->hdr->continues) { ctx->hdr->use_full_value = TRUE; return; } ret = search_sent(arg->type, arg->value.time, ctx->hdr->full_value, ctx->hdr->full_value_len); ARG_SET_RESULT(arg, ret); } return; case SEARCH_HEADER: case SEARCH_HEADER_ADDRESS: case SEARCH_HEADER_COMPRESS_LWSP: ctx->custom_header = TRUE; if (strcasecmp(ctx->hdr->name, arg->hdr_field_name) != 0) return; break; default: return; } if (arg->value.str[0] == '\0') { /* we're just testing existence of the field. always matches. */ ARG_SET_RESULT(arg, 1); return; } if (ctx->hdr->continues) { ctx->hdr->use_full_value = TRUE; return; } memset(&block, 0, sizeof(block)); /* We're searching only for values, so drop header name and middle parts. We use header searching so that MIME words will be decoded. */ hdr = *ctx->hdr; hdr.name = ""; hdr.name_len = 0; hdr.middle_len = 0; block.hdr = &hdr; msg_search_ctx = msg_search_arg_context(ctx->index_context, arg); if (msg_search_ctx == NULL) return; T_BEGIN { struct message_address *addr; string_t *str; switch (arg->type) { case SEARCH_HEADER: /* simple match */ break; case SEARCH_HEADER_ADDRESS: /* we have to match against normalized address */ addr = message_address_parse(pool_datastack_create(), ctx->hdr->full_value, ctx->hdr->full_value_len, (unsigned int)-1, TRUE); str = t_str_new(ctx->hdr->value_len); message_address_write(str, addr); hdr.value = hdr.full_value = str_data(str); hdr.value_len = hdr.full_value_len = str_len(str); break; case SEARCH_HEADER_COMPRESS_LWSP: /* convert LWSP to single spaces */ str = t_str_new(hdr.full_value_len); compress_lwsp(str, hdr.full_value, hdr.full_value_len); hdr.value = hdr.full_value = str_data(str); hdr.value_len = hdr.full_value_len = str_len(str); break; default: i_unreached(); } ret = message_search_more(msg_search_ctx, &block) ? 1 : 0; } T_END; /* there may be multiple headers. don't mark this failed yet. */ if (ret > 0) ARG_SET_RESULT(arg, 1); }