]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
fts: Work harder to find attachment filename
authorFred Morcos <fred.morcos@open-xchange.com>
Fri, 18 Jul 2025 08:38:38 +0000 (10:38 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Tue, 22 Jul 2025 07:51:47 +0000 (07:51 +0000)
src/plugins/fts/fts-build-mail.c
src/plugins/fts/fts-parser-script.c
src/plugins/fts/fts-parser.h

index 034e4605e1d2537ee50ebc1983378ae569d4bc86..d674cfea121c23dd4177262ad3ce13febea5678f 100644 (file)
@@ -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);
index 2374624cb2a99e51ce208e37301e2dc6ffce6835..d05c1b823ef7073e60d177c73a9d685b43fa2d9c 100644 (file)
@@ -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;
 
index a04126da4eeb3d948fddd3ee9e2e675619b383ca..904433caabf9d87a856ce9006ab78359baa6d4e6 100644 (file)
@@ -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;
 };