From: Fred Morcos Date: Fri, 18 Jul 2025 08:38:38 +0000 (+0200) Subject: fts: Work harder to find attachment filename X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=712f53a0a19ca5f89917b7deaf9ebe6e7b73477d;p=thirdparty%2Fdovecot%2Fcore.git fts: Work harder to find attachment filename --- diff --git a/src/plugins/fts/fts-build-mail.c b/src/plugins/fts/fts-build-mail.c index 034e4605e1..d674cfea12 100644 --- a/src/plugins/fts/fts-build-mail.c +++ b/src/plugins/fts/fts-build-mail.c @@ -30,7 +30,7 @@ struct fts_mail_build_context { struct mail *mail; struct fts_backend_update_context *update_ctx; - char *content_type, *content_disposition; + char *content_type, *content_type_params, *content_disposition; struct fts_parser *body_parser; buffer_t *word_buf, *pending_input; @@ -55,7 +55,12 @@ static void fts_build_parse_content_type(struct fts_mail_build_context *ctx, T_BEGIN { content_type = t_str_new(64); (void)rfc822_parse_content_type(&parser, content_type); + /* Parse the mime-type only... */ ctx->content_type = str_lcase(i_strdup(str_c(content_type))); + /* ... then store the remainder of the line - which may contain RFC2231 + parameters - without parsing it because not all backends need them. In + the backends that need them further parsing can be implemented. */ + ctx->content_type_params = i_strdup((const char *)parser.data); } T_END; rfc822_parser_deinit(&parser); } @@ -214,8 +219,14 @@ fts_build_body_begin(struct fts_mail_build_context *ctx, key.part = part; i_zero(&parser_context); - parser_context.content_type = ctx->content_type != NULL ? - ctx->content_type : "text/plain"; + if (ctx->content_type != NULL) { + parser_context.content_type = ctx->content_type; + parser_context.content_type_params = ctx->content_type_params; + } else { + parser_context.content_type = "text/plain"; + parser_context.content_type_params = ""; + } + if (str_begins_with(parser_context.content_type, "multipart/")) { /* multiparts are never indexed, only their contents */ return FALSE; @@ -641,6 +652,7 @@ fts_build_mail_real(struct fts_backend_update_context *update_ctx, fts_backend_update_unset_build_key(update_ctx); prev_part = raw_block.part; i_free_and_null(ctx.content_type); + i_free_and_null(ctx.content_type_params); i_free_and_null(ctx.content_disposition); if (raw_block.size != 0) { @@ -721,6 +733,7 @@ fts_build_mail_real(struct fts_backend_update_context *update_ctx, index_mail_set_message_parts_corrupted(mail, error); message_decoder_deinit(&decoder); i_free(ctx.content_type); + i_free(ctx.content_type_params); i_free(ctx.content_disposition); buffer_free(&ctx.word_buf); buffer_free(&ctx.pending_input); diff --git a/src/plugins/fts/fts-parser-script.c b/src/plugins/fts/fts-parser-script.c index 2374624cb2..d05c1b823e 100644 --- a/src/plugins/fts/fts-parser-script.c +++ b/src/plugins/fts/fts-parser-script.c @@ -161,37 +161,55 @@ static bool script_support_content(struct fts_parser_context *parser_context, return FALSE; } -static void parse_content_disposition(const char *content_disposition, - const char **filename_r) +static bool get_param_and_free_parser(struct rfc822_parser_context *parser, + const char *key, const char **value_r) { - struct rfc822_parser_context parser; const char *const *results; - string_t *str; + *value_r = NULL; + rfc2231_parse(parser, &results); + for (; *results != NULL; results += 2) { + if (strcasecmp(results[0], key) == 0) { + *value_r = results[1]; + break; + } + } + rfc822_parser_deinit(parser); + return *value_r != NULL; +} - *filename_r = NULL; +static struct rfc822_parser_context init_content_parser(const char *content) +{ + struct rfc822_parser_context parser; + rfc822_parser_init(&parser, (const unsigned char *)content, strlen(content), NULL); + rfc822_skip_lwsp(&parser); + return parser; +} - if (content_disposition == NULL) - return; +/* We receive Content-Disposition parameters as `mimetype; param; param; ...` */ +static bool get_cd_filename(const char *content, const char **filename_r) +{ + if (content == NULL) + return FALSE; - rfc822_parser_init(&parser, (const unsigned char *)content_disposition, - strlen(content_disposition), NULL); - rfc822_skip_lwsp(&parser); + struct rfc822_parser_context parser = init_content_parser(content); /* type; param; param; .. */ - str = t_str_new(32); + string_t *str = t_str_new(32); if (rfc822_parse_mime_token(&parser, str) < 0) { rfc822_parser_deinit(&parser); - return; + return FALSE; } - rfc2231_parse(&parser, &results); - for (; *results != NULL; results += 2) { - if (strcasecmp(results[0], "filename") == 0) { - *filename_r = results[1]; - break; - } - } - rfc822_parser_deinit(&parser); + return get_param_and_free_parser(&parser, "filename", filename_r); +} + +/* We receive Content-Type parameters as `; param; param; ...` */ +static bool get_ct_filename(const char *content, const char **filename_r) +{ + if (content == NULL) + return FALSE; + struct rfc822_parser_context parser = init_content_parser(content); + return get_param_and_free_parser(&parser, "name", filename_r); } static struct fts_parser * @@ -202,7 +220,9 @@ fts_parser_script_try_init(struct fts_parser_context *parser_context) const char *filename, *path, *cmd; int fd; - parse_content_disposition(parser_context->content_disposition, &filename); + if (!get_cd_filename(parser_context->content_disposition, &filename)) + (void)get_ct_filename(parser_context->content_type_params, &filename); + if (!script_support_content(parser_context, filename)) return NULL; diff --git a/src/plugins/fts/fts-parser.h b/src/plugins/fts/fts-parser.h index a04126da4e..904433caab 100644 --- a/src/plugins/fts/fts-parser.h +++ b/src/plugins/fts/fts-parser.h @@ -9,6 +9,7 @@ struct fts_parser_context { struct mail_user *user; /* Can't be NULL */ const char *content_type; + const char *content_type_params; const char *content_disposition; struct event *event; };