]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-imap: imap-bodystructure - Add UTF8 support for BODYSTRUCTURE encoding
authorStephan Bosch <stephan.bosch@open-xchange.com>
Tue, 26 Aug 2025 01:29:52 +0000 (03:29 +0200)
committerStephan Bosch <stephan.bosch@open-xchange.com>
Mon, 26 Jan 2026 01:58:58 +0000 (02:58 +0100)
src/lib-imap-storage/imap-msgpart.c
src/lib-imap/fuzz-imap-bodystructure.c
src/lib-imap/imap-bodystructure.c
src/lib-imap/imap-bodystructure.h
src/lib-imap/test-imap-bodystructure.c
src/lib-storage/index/imapc/imapc-mail-fetch.c
src/lib-storage/index/index-mail.c

index 7f1acb445bc2b04e049191ff569f617e2d5727f2..81e3617ce1b19b72b46513b88732ac8cfc7551ad 100644 (file)
@@ -847,7 +847,8 @@ int imap_msgpart_bodypartstructure(struct mail *mail,
 
        if (ret >= 0) {
                bpstruct = t_str_new(256);
-               if (imap_bodystructure_write(part, bpstruct, TRUE, &error) < 0) {
+               if (imap_bodystructure_write(part, bpstruct, TRUE, FALSE,
+                                            &error) < 0) {
                        error = t_strdup_printf(
                                "Invalid message_part/BODYSTRUCTURE: %s", error);
                        mail_set_cache_corrupted(mail, MAIL_FETCH_MESSAGE_PARTS,
index 1cf66cd1142f64707f8d4e7a448e3a81235f1525..69f7d1d6b74c21da050f8c9f23af072dbb19ce0c 100644 (file)
@@ -130,7 +130,7 @@ FUZZ_BEGIN_STR(const char *bodystruct_orig)
        if (imap_bodystructure_parse_full(
                bodystruct_orig, pool, &parts_orig, &error) == 0) {
                if (imap_bodystructure_write(
-                       parts_orig, buffer, TRUE, &error) != 0)
+                       parts_orig, buffer, TRUE, 0, &error) != 0)
                        i_panic("Failed to write bodystructure: %s", error);
                bodystruct_regen = t_strdup(str_c(buffer));
 
index f7a82db45dbbaba053a592ffdf0f7054b9c00fbb..e3d4b3b56401b45f8b1bb95a47b7f9354ba17975 100644 (file)
@@ -31,9 +31,8 @@
  */
 
 static void
-params_write(const struct message_part_param *params,
-       unsigned int params_count, string_t *str,
-       bool default_charset)
+params_write(const struct message_part_param *params, unsigned int params_count,
+            string_t *str, bool default_charset, enum imap_quote_flags qflags)
 {
        unsigned int i;
        bool seen_charset;
@@ -54,9 +53,9 @@ params_write(const struct message_part_param *params,
                if (default_charset &&
                        strcasecmp(params[i].name, "charset") == 0)
                        seen_charset = TRUE;
-               imap_append_string(str, params[i].name, 0);
+               imap_append_string(str, params[i].name, qflags);
                str_append_c(str, ' ');
-               imap_append_string(str, params[i].value, 0);
+               imap_append_string(str, params[i].value, qflags);
        }
        if (default_charset && !seen_charset) {
                if (i > 0)
@@ -70,11 +69,13 @@ params_write(const struct message_part_param *params,
 static int
 part_write_bodystructure_siblings(const struct message_part *part,
                                  string_t *dest, bool extended,
+                                 enum imap_quote_flags qflags,
                                  const char **error_r)
 {
        for (; part != NULL; part = part->next) {
                str_append_c(dest, '(');
-               if (imap_bodystructure_write(part, dest, extended, error_r) < 0)
+               if (imap_bodystructure_write(part, dest, extended, qflags,
+                                            error_r) < 0)
                        return -1;
                str_append_c(dest, ')');
        }
@@ -83,18 +84,19 @@ part_write_bodystructure_siblings(const struct message_part *part,
 
 static void
 part_write_bodystructure_common(const struct message_part_data *data,
-                                    string_t *str)
+                               string_t *str, enum imap_quote_flags qflags)
 {
        str_append_c(str, ' ');
        if (data->content_disposition == NULL)
                str_append(str, "NIL");
        else {
                str_append_c(str, '(');
-               imap_append_string(str, data->content_disposition, 0);
+               imap_append_string(str, data->content_disposition, qflags);
 
                str_append_c(str, ' ');
                params_write(data->content_disposition_params,
-                       data->content_disposition_params_count, str, FALSE);
+                       data->content_disposition_params_count, str,
+                       FALSE, qflags);
 
                str_append_c(str, ')');
        }
@@ -107,22 +109,23 @@ part_write_bodystructure_common(const struct message_part_data *data,
 
                i_assert(*lang != NULL);
                str_append_c(str, '(');
-               imap_append_string(str, *lang, 0);
+               imap_append_string(str, *lang, qflags);
                lang++;
                while (*lang != NULL) {
                        str_append_c(str, ' ');
-                       imap_append_string(str, *lang, 0);
+                       imap_append_string(str, *lang, qflags);
                        lang++;
                }
                str_append_c(str, ')');
        }
 
        str_append_c(str, ' ');
-       imap_append_nstring_nolf(str, data->content_location, 0);
+       imap_append_nstring_nolf(str, data->content_location, qflags);
 }
 
 static int part_write_body_multipart(const struct message_part *part,
                                     string_t *str, bool extended,
+                                    enum imap_quote_flags qflags,
                                     const char **error_r)
 {
        const struct message_part_data *data = part->data;
@@ -131,7 +134,8 @@ static int part_write_body_multipart(const struct message_part *part,
 
        if (part->children != NULL) {
                if (part_write_bodystructure_siblings(part->children, str,
-                                                     extended, error_r) < 0)
+                                                     extended, qflags,
+                                                     error_r) < 0)
                        return -1;
        } else {
                /* no parts in multipart message,
@@ -144,7 +148,7 @@ static int part_write_body_multipart(const struct message_part *part,
        }
 
        str_append_c(str, ' ');
-       imap_append_string(str, data->content_subtype, 0);
+       imap_append_string(str, data->content_subtype, qflags);
 
        if (!extended)
                return 0;
@@ -153,9 +157,9 @@ static int part_write_body_multipart(const struct message_part *part,
 
        str_append_c(str, ' ');
        params_write(data->content_type_params,
-               data->content_type_params_count, str, FALSE);
+               data->content_type_params_count, str, FALSE, qflags);
 
-       part_write_bodystructure_common(data, str);
+       part_write_bodystructure_common(data, str, qflags);
        return 0;
 }
 
@@ -190,8 +194,10 @@ static bool part_is_truncated(const struct message_part *part)
        return FALSE;
 }
 
-static int part_write_body(const struct message_part *part,
-                          string_t *str, bool extended, const char **error_r)
+static int
+part_write_body(const struct message_part *part, string_t *str,
+               bool extended, enum imap_quote_flags qflags,
+               const char **error_r)
 {
        const struct message_part_data *data = part->data;
        bool text;
@@ -216,9 +222,9 @@ static int part_write_body(const struct message_part *part,
                        str_append(str, "\"text\" \"plain\"");
                } else {
                        text = (strcasecmp(data->content_type, "text") == 0);
-                       imap_append_string(str, data->content_type, 0);
+                       imap_append_string(str, data->content_type, qflags);
                        str_append_c(str, ' ');
-                       imap_append_string(str, data->content_subtype, 0);
+                       imap_append_string(str, data->content_subtype, qflags);
                }
                bool part_is_text = (part->flags & MESSAGE_PART_FLAG_TEXT) != 0;
                if (text != part_is_text) {
@@ -230,15 +236,15 @@ static int part_write_body(const struct message_part *part,
        /* ("content type param key" "value" ...) */
        str_append_c(str, ' ');
        params_write(data->content_type_params,
-               data->content_type_params_count, str, text);
+               data->content_type_params_count, str, text, qflags);
 
        str_append_c(str, ' ');
-       imap_append_nstring_nolf(str, data->content_id, 0);
+       imap_append_nstring_nolf(str, data->content_id, qflags);
        str_append_c(str, ' ');
-       imap_append_nstring_nolf(str, data->content_description, 0);
+       imap_append_nstring_nolf(str, data->content_description, qflags);
        str_append_c(str, ' ');
        if (data->content_transfer_encoding != NULL)
-               imap_append_string(str, data->content_transfer_encoding, 0);
+               imap_append_string(str, data->content_transfer_encoding, qflags);
        else
                str_append(str, "\"7bit\"");
        str_printfa(str, " %"PRIuUOFF_T, part->body_size.virtual_size);
@@ -256,11 +262,12 @@ static int part_write_body(const struct message_part *part,
                child_data = part->children->data;
 
                str_append(str, " (");
-               imap_envelope_write(child_data->envelope, str, 0);
+               imap_envelope_write(child_data->envelope, str, qflags);
                str_append(str, ") ");
 
                if (part_write_bodystructure_siblings(part->children, str,
-                                                     extended, error_r) < 0)
+                                                     extended, qflags,
+                                                     error_r) < 0)
                        return -1;
                str_printfa(str, " %u", part->body_size.lines);
        }
@@ -273,19 +280,22 @@ static int part_write_body(const struct message_part *part,
        /* "md5" ("content disposition" ("disposition" "params"))
           ("body" "language" "params") "location" */
        str_append_c(str, ' ');
-       imap_append_nstring_nolf(str, data->content_md5, 0);
-       part_write_bodystructure_common(data, str);
+       imap_append_nstring_nolf(str, data->content_md5, qflags);
+       part_write_bodystructure_common(data, str, qflags);
        return 0;
 }
 
 int imap_bodystructure_write(const struct message_part *part,
                             string_t *dest, bool extended,
+                            enum imap_quote_flags qflags,
                             const char **error_r)
 {
-       if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0)
-               return part_write_body_multipart(part, dest, extended, error_r);
-       else
-               return part_write_body(part, dest, extended, error_r);
+       if ((part->flags & MESSAGE_PART_FLAG_MULTIPART) != 0) {
+               return part_write_body_multipart(part, dest, extended, qflags,
+                                                error_r);
+       } else {
+               return part_write_body(part, dest, extended, qflags, error_r);
+       }
 }
 
 /*
index a7cc6cda7baafe2d5079d2d7e72ee11fc39e3511..dfc610b7f3c5959b28677b2c919e03a96dc5c567 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef IMAP_BODYSTRUCTURE_H
 #define IMAP_BODYSTRUCTURE_H
 
+#include "imap-quote.h"
+
 struct message_part;
 struct message_header_line;
 struct imap_arg;
@@ -11,6 +13,7 @@ struct imap_arg;
    (e.g. broken cached mime.parts mixed with parsed message). */
 int imap_bodystructure_write(const struct message_part *part,
                             string_t *dest, bool extended,
+                            enum imap_quote_flags qflags,
                             const char **error_r);
 
 /* Parse BODYSTRUCTURE and save the contents to message_part->data for each
index 40c8a8c6ecca371ed91036f3d9aff558adb065f7..28b2f7800f5f432f0c23fa9860cfcc62c26ed227 100644 (file)
@@ -425,11 +425,11 @@ static void test_imap_bodystructure_write(void)
                test_begin(t_strdup_printf("imap bodystructure write [%u]", i));
                parts = msg_parse(pool, test->message, 0, 0, TRUE);
 
-               test_assert(imap_bodystructure_write(parts, str, TRUE, &error) == 0);
+               test_assert(imap_bodystructure_write(parts, str, TRUE, 0, &error) == 0);
                test_assert(strcmp(str_c(str), test->bodystructure) == 0);
 
                str_truncate(str, 0);
-               test_assert(imap_bodystructure_write(parts, str, FALSE, &error) == 0);
+               test_assert(imap_bodystructure_write(parts, str, FALSE, 0, &error) == 0);
                test_assert(strcmp(str_c(str), test->body) == 0);
 
                pool_unref(&pool);
@@ -445,7 +445,7 @@ static void test_imap_bodystructure_write(void)
                parts->flags &= ENUM_NEGATE(MESSAGE_PART_FLAG_TEXT);
 
                string_t *str = t_str_new(128);
-               test_assert(imap_bodystructure_write(parts, str, FALSE, &error) < 0);
+               test_assert(imap_bodystructure_write(parts, str, FALSE, 0, &error) < 0);
                test_assert_strcmp(error, "text flag mismatch");
                pool_unref(&pool);
                test_end();
@@ -477,7 +477,7 @@ static void test_imap_bodystructure_parse(void)
 
                if (ret == 0) {
                        str_truncate(str, 0);
-                       test_assert(imap_bodystructure_write(parts, str, TRUE, &error) == 0);
+                       test_assert(imap_bodystructure_write(parts, str, TRUE, 0, &error) == 0);
                        test_assert(strcmp(str_c(str), test->bodystructure) == 0);
                } else {
                        i_error("Invalid BODYSTRUCTURE: %s", error);
@@ -581,7 +581,7 @@ static void test_imap_bodystructure_parse_full(void)
 
                if (ret == 0) {
                        str_truncate(str, 0);
-                       test_assert(imap_bodystructure_write(parts, str, TRUE, &error) == 0);
+                       test_assert(imap_bodystructure_write(parts, str, TRUE, 0, &error) == 0);
                        test_assert(strcmp(str_c(str), test->bodystructure) == 0);
                } else {
                        i_error("Invalid BODYSTRUCTURE: %s", error);
@@ -613,7 +613,7 @@ static void test_imap_bodystructure_normalize(void)
 
                if (ret == 0) {
                        str_truncate(str, 0);
-                       test_assert(imap_bodystructure_write(parts, str, TRUE, &error) == 0);
+                       test_assert(imap_bodystructure_write(parts, str, TRUE, 0, &error) == 0);
                        test_assert(strcmp(str_c(str), test->output) == 0);
                } else {
                        i_error("Invalid BODYSTRUCTURE: %s", error);
@@ -702,7 +702,7 @@ static void test_imap_bodystructure_truncation(void)
                                  TRUE);
 
                /* write out BODYSTRUCTURE and serialize message_parts */
-               test_assert(imap_bodystructure_write(parts, str_body, TRUE, &error) == 0);
+               test_assert(imap_bodystructure_write(parts, str_body, TRUE, 0, &error) == 0);
                message_part_serialize(parts, str_parts);
 
                /* now deserialize message_parts and make sure they can be used
index dc9e5ffcf9ca22ad0451138ed3a929e1e88e392e..35692a3bd51032808790c33308c6992198e251cb 100644 (file)
@@ -809,7 +809,8 @@ imapc_args_to_bodystructure(struct imapc_mail *mail,
                ret = NULL;
        } else {
                string_t *str = t_str_new(128);
-               if (imap_bodystructure_write(parts, str, extended, &error) < 0) {
+               if (imap_bodystructure_write(parts, str, extended, 0,
+                                            &error) < 0) {
                        /* All the input to imap_bodystructure_write() came
                           from imap_bodystructure_parse_args(). We should never
                           get here. Instead, if something is wrong the
index 99f045fae8275387bbbc0a7b49f074597a3d9301..214570d34649323b9a794f12109c7b532f97d68f 100644 (file)
@@ -824,7 +824,7 @@ index_mail_write_bodystructure(struct index_mail *mail, string_t *str,
 {
        const char *error;
 
-       if (imap_bodystructure_write(mail->data.parts, str, extended,
+       if (imap_bodystructure_write(mail->data.parts, str, extended, FALSE,
                                     &error) < 0) {
                mail_set_cache_corrupted(&mail->mail.mail,
                        MAIL_FETCH_MESSAGE_PARTS, error);