]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
IMAP protocol doesn't allow server to send NULs to client. Send ascii #128
authorTimo Sirainen <tss@iki.fi>
Wed, 4 Jun 2003 15:57:58 +0000 (18:57 +0300)
committerTimo Sirainen <tss@iki.fi>
Wed, 4 Jun 2003 15:57:58 +0000 (18:57 +0300)
instead.

--HG--
branch : HEAD

12 files changed:
src/imap/imap-fetch-body-section.c
src/imap/imap-fetch.c
src/lib-index/mail-index-update.c
src/lib-index/mail-index.h
src/lib-mail/message-parser.c
src/lib-mail/message-parser.h
src/lib-mail/message-send.c
src/lib-mail/message-send.h
src/lib-mail/message-size.c
src/lib-mail/message-size.h
src/lib-storage/index/index-mail.c
src/lib-storage/mail-storage.h

index ba49ec2aa67b6dd0ea3487b68d2ff8b175bb3d20..b4be84e9281b48558eedfb25494219ffa442cee9 100644 (file)
@@ -27,6 +27,8 @@ struct fetch_header_field_context {
        uoff_t skip, max_size;
        const char *const *fields;
        int (*match_func) (const char *const *, const char *, size_t);
+
+       unsigned int fix_nuls:1;
 };
 
 struct partial_cache {
@@ -103,7 +105,8 @@ static int fetch_body(struct imap_fetch_context *ctx,
                               body->skip);
 
        ret = message_send(ctx->output, stream, &body_size,
-                          skip_cr, body->max_size, &last_cr);
+                          skip_cr, body->max_size, &last_cr,
+                          !mail->has_no_nuls);
        if (ret > 0) {
                partial.cr_skipped = last_cr != 0;
                partial.pos.physical_size =
@@ -189,6 +192,7 @@ static int fetch_header_append(struct fetch_header_field_context *ctx,
                               const void *data, size_t size)
 {
        const unsigned char *str = data;
+       size_t i;
 
        if (ctx->skip > 0) {
                if (ctx->skip >= size) {
@@ -206,14 +210,38 @@ static int fetch_header_append(struct fetch_header_field_context *ctx,
                size = ctx->max_size - ctx->dest_size;
        }
 
-       if (ctx->dest != NULL)
-               buffer_append(ctx->dest, str, size);
        ctx->dest_size += size;
 
+       if (ctx->fix_nuls && (ctx->dest != NULL || ctx->output != NULL)) {
+               for (i = 0; i < size; ) {
+                       if (str[i] != 0) {
+                               i++;
+                               continue;
+                       }
+
+                       /* NUL found, change it to #128 */
+                       if (ctx->dest != NULL) {
+                               buffer_append(ctx->dest, str, i);
+                               buffer_append(ctx->dest, "\x80", 1);
+                       } else {
+                               if (o_stream_send(ctx->output, str, i) < 0 ||
+                                   o_stream_send(ctx->output, "\x80", 1) < 0)
+                                       return FALSE;
+                       }
+
+                       str += i+1;
+                       size -= i+1;
+                       i = 0;
+               }
+       }
+
+       if (ctx->dest != NULL)
+               buffer_append(ctx->dest, str, size);
        if (ctx->output != NULL) {
                if (o_stream_send(ctx->output, str, size) < 0)
                        return FALSE;
        }
+
        return ctx->dest_size < ctx->max_size;
 }
 
@@ -272,7 +300,7 @@ static int fetch_header_fields(struct istream *input, const char *section,
 /* fetch wanted headers from given data */
 static int fetch_header_from(struct imap_fetch_context *ctx,
                             struct istream *input,
-                            const struct message_size *size,
+                            const struct message_size *size, struct mail *mail,
                             const struct imap_fetch_body_data *body,
                             const char *header_section)
 {
@@ -292,7 +320,8 @@ static int fetch_header_from(struct imap_fetch_context *ctx,
                if (o_stream_send_str(ctx->output, str) < 0)
                        return FALSE;
                return message_send(ctx->output, input, size,
-                                   body->skip, body->max_size, NULL) >= 0;
+                                   body->skip, body->max_size, NULL,
+                                   !mail->has_no_nuls) >= 0;
        }
 
        /* partial headers - copy the wanted fields into memory, inserting
@@ -302,6 +331,7 @@ static int fetch_header_from(struct imap_fetch_context *ctx,
        memset(&hdr_ctx, 0, sizeof(hdr_ctx));
        hdr_ctx.skip = body->skip;
        hdr_ctx.max_size = body->max_size;
+       hdr_ctx.fix_nuls = !mail->has_no_nuls;
 
        failed = FALSE;
        start_offset = input->v_offset;
@@ -366,7 +396,8 @@ static int fetch_header(struct imap_fetch_context *ctx, struct mail *mail,
        if (stream == NULL)
                return FALSE;
 
-       return fetch_header_from(ctx, stream, &hdr_size, body, body->section);
+       return fetch_header_from(ctx, stream, &hdr_size,
+                                mail, body, body->section);
 }
 
 /* Find message_part for section (eg. 1.3.4) */
@@ -443,7 +474,8 @@ static int fetch_part_body(struct imap_fetch_context *ctx,
                               &partial, stream, part->physical_pos +
                               part->header_size.physical_size, body->skip);
        ret = message_send(ctx->output, stream, &part->body_size,
-                          skip_cr, body->max_size, &last_cr);
+                          skip_cr, body->max_size, &last_cr,
+                          !mail->has_no_nuls);
        if (ret > 0) {
                partial.cr_skipped = last_cr != 0;
                partial.pos.physical_size =
@@ -475,7 +507,7 @@ static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail,
            strcmp(section, "MIME") == 0) {
                i_stream_seek(stream, part->physical_pos);
                return fetch_header_from(ctx, stream, &part->header_size,
-                                        body, section);
+                                        mail, body, section);
        }
 
        i_warning("BUG: Accepted invalid section from user: '%s'",
index 66e61a656fcc2133be393689c887e344c6a2598f..b7c014053817e84c5870c734c3c45f04535dc5a2 100644 (file)
@@ -113,7 +113,7 @@ static int fetch_send_rfc822(struct imap_fetch_context *ctx, struct mail *mail)
                return FALSE;
 
        return message_send(ctx->output, stream, &body_size,
-                           0, (uoff_t)-1, NULL) >= 0;
+                           0, (uoff_t)-1, NULL, !mail->has_no_nuls) >= 0;
 }
 
 static int fetch_send_rfc822_header(struct imap_fetch_context *ctx,
@@ -136,7 +136,7 @@ static int fetch_send_rfc822_header(struct imap_fetch_context *ctx,
                return FALSE;
 
        return message_send(ctx->output, stream, &hdr_size,
-                           0, (uoff_t)-1, NULL) >= 0;
+                           0, (uoff_t)-1, NULL, !mail->has_no_nuls) >= 0;
 }
 
 static int fetch_send_rfc822_text(struct imap_fetch_context *ctx,
@@ -160,7 +160,7 @@ static int fetch_send_rfc822_text(struct imap_fetch_context *ctx,
 
        i_stream_seek(stream, hdr_size.physical_size);
        return message_send(ctx->output, stream, &body_size,
-                           0, (uoff_t)-1, NULL) >= 0;
+                           0, (uoff_t)-1, NULL, !mail->has_no_nuls) >= 0;
 }
 
 static int fetch_mail(struct imap_fetch_context *ctx, struct mail *mail)
index 0f493c66953b098f5473c7478ed70c0581b18d49..db680a5c8db761c841910ef609eedf2c7dfef002 100644 (file)
@@ -459,6 +459,13 @@ void mail_index_update_headers(struct mail_index_update *update,
                if (part == NULL) {
                        part = message_parse(pool, input,
                                             update_header_cb, &ctx);
+                       if ((part->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
+                               update->rec->index_flags |=
+                                       INDEX_MAIL_FLAG_HAS_NULS;
+                       } else {
+                               update->rec->index_flags |=
+                                       INDEX_MAIL_FLAG_HAS_NO_NULS;
+                       }
                } else {
                        /* cached, construct the bodystructure using it.
                           also we need to parse the header.. */
index 0915c228f69aacea0f7c2d82d6f8351e2870f542..36b5abf40eb44931db419378751a4ea2e5b987ca 100644 (file)
@@ -75,7 +75,12 @@ enum mail_index_mail_flag {
        INDEX_MAIL_FLAG_DIRTY           = 0x0004,
 
        /* Maildir: Mail file is in new/ dir instead of cur/ */
-       INDEX_MAIL_FLAG_MAILDIR_NEW     = 0x0008
+       INDEX_MAIL_FLAG_MAILDIR_NEW     = 0x0008,
+
+       /* Mail header or body is known to contain NUL characters. */
+       INDEX_MAIL_FLAG_HAS_NULS        = 0x0010,
+       /* Mail header or body is known to not contain NUL characters. */
+       INDEX_MAIL_FLAG_HAS_NO_NULS     = 0x0020
 };
 
 enum mail_lock_type {
index d1f7f51dffd56dd4340703170e962dca9fae11dc..90e5bb0b8ceab16262adb7ba779353475aba783d 100644 (file)
@@ -38,6 +38,8 @@ struct message_header_parser_ctx {
        string_t *name;
        buffer_t *value_buf;
        size_t skip;
+
+       int has_nuls;
 };
 
 static struct message_part *
@@ -46,12 +48,12 @@ message_parse_part(struct istream *input,
 
 static struct message_part *
 message_parse_body(struct istream *input, struct message_boundary *boundaries,
-                  struct message_size *body_size);
+                  struct message_size *body_size, int *has_nuls);
 
 static struct message_part *
 message_skip_boundary(struct istream *input,
                      struct message_boundary *boundaries,
-                     struct message_size *boundary_size);
+                     struct message_size *boundary_size, int *has_nuls);
 
 static void message_size_add_part(struct message_size *dest,
                                  struct message_part *part)
@@ -138,6 +140,7 @@ message_parse_multipart(struct istream *input,
 {
        struct message_part *parent_part, *next_part, *part;
        struct message_boundary *b;
+       int has_nuls;
 
        /* multipart message. add new boundary */
        b = t_new(struct message_boundary, 1);
@@ -155,7 +158,9 @@ message_parse_multipart(struct istream *input,
        /* skip the data before the first boundary */
        parent_part = parser_ctx->part;
        next_part = message_skip_boundary(input, parser_ctx->boundaries,
-                                         &parent_part->body_size);
+                                         &parent_part->body_size, &has_nuls);
+       if (has_nuls)
+               parent_part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
 
        /* now, parse the parts */
        while (next_part == parent_part) {
@@ -165,6 +170,11 @@ message_parse_multipart(struct istream *input,
                 parser_ctx->part = part;
                next_part = message_parse_part(input, parser_ctx);
 
+               if ((part->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
+                       /* it also belongs to parent */
+                       parent_part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
+               }
+
                /* update our size */
                message_size_add_part(&parent_part->body_size, part);
 
@@ -173,7 +183,10 @@ message_parse_multipart(struct istream *input,
 
                /* skip the boundary */
                next_part = message_skip_boundary(input, parser_ctx->boundaries,
-                                                 &parent_part->body_size);
+                                                 &parent_part->body_size,
+                                                 &has_nuls);
+               if (has_nuls)
+                       parent_part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
        }
 
        /* remove boundary */
@@ -192,6 +205,7 @@ message_parse_part(struct istream *input, struct parser_context *parser_ctx)
        struct message_header_line *hdr;
        struct message_part *next_part, *part;
        uoff_t hdr_size;
+       int has_nuls;
 
        hdr_ctx = message_parse_header_init(input,
                                            &parser_ctx->part->header_size);
@@ -219,6 +233,8 @@ message_parse_part(struct istream *input, struct parser_context *parser_ctx)
                parser_ctx->callback(parser_ctx->part, NULL,
                                     parser_ctx->context);
        }
+       if (hdr_ctx->has_nuls)
+               parser_ctx->part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
        message_parse_header_deinit(hdr_ctx);
 
        i_assert((parser_ctx->part->flags & MUTEX_FLAGS) != MUTEX_FLAGS);
@@ -263,23 +279,35 @@ message_parse_part(struct istream *input, struct parser_context *parser_ctx)
                /* normal message, read until the next boundary */
                part = parser_ctx->part;
                next_part = message_parse_body(input, parser_ctx->boundaries,
-                                              &part->body_size);
+                                              &part->body_size, &has_nuls);
+               if (has_nuls)
+                       part->flags |= MESSAGE_PART_FLAG_HAS_NULS;
+       }
+
+       if ((part->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0 &&
+           part->parent != NULL) {
+               /* it also belongs to parent */
+               part->parent->flags |= MESSAGE_PART_FLAG_HAS_NULS;
        }
 
        return next_part;
 }
 
 static void message_skip_line(struct istream *input,
-                             struct message_size *msg_size, int skip_lf)
+                             struct message_size *msg_size, int skip_lf,
+                             int *has_nuls)
 {
        const unsigned char *msg;
        size_t i, size, startpos;
 
        startpos = 0;
+       *has_nuls = FALSE;
 
        while (i_stream_read_data(input, &msg, &size, startpos) > 0) {
                for (i = startpos; i < size; i++) {
-                       if (msg[i] == '\n') {
+                       if (msg[i] == '\0')
+                               *has_nuls = TRUE;
+                       else if (msg[i] == '\n') {
                                if (!skip_lf) {
                                        if (i > 0 && msg[i-1] == '\r')
                                                i--;
@@ -336,7 +364,8 @@ boundary_find(struct message_boundary *boundaries,
 static struct message_boundary *
 message_find_boundary(struct istream *input,
                      struct message_boundary *boundaries,
-                     struct message_size *msg_size, int skip_over)
+                     struct message_size *msg_size, int skip_over,
+                     int *has_nuls)
 {
        struct message_boundary *boundary;
        const unsigned char *msg;
@@ -344,11 +373,15 @@ message_find_boundary(struct istream *input,
 
        boundary = NULL;
        missing_cr_count = startpos = line_start = 0;
+       *has_nuls = FALSE;
 
        while (i_stream_read_data(input, &msg, &size, startpos) > 0) {
                for (i = startpos; i < size; i++) {
-                       if (msg[i] != '\n')
+                       if (msg[i] != '\n') {
+                               if (msg[i] == '\0')
+                                       *has_nuls = TRUE;
                                continue;
+                       }
 
                        if (line_start != (size_t)-1 &&
                            i >= line_start+2 && msg[line_start] == '-' &&
@@ -447,20 +480,22 @@ message_find_boundary(struct istream *input,
 
 static struct message_part *
 message_parse_body(struct istream *input, struct message_boundary *boundaries,
-                  struct message_size *msg_size)
+                  struct message_size *msg_size, int *has_nuls)
 {
        struct message_boundary *boundary;
        struct message_size body_size;
 
        if (boundaries == NULL) {
-               message_get_body_size(input, &body_size, (uoff_t)-1, NULL);
+               message_get_body_size(input, &body_size,
+                                     (uoff_t)-1, NULL, has_nuls);
                message_size_add(msg_size, &body_size);
-               return NULL;
+               boundary = NULL;
        } else {
                boundary = message_find_boundary(input, boundaries,
-                                                msg_size, FALSE);
-               return boundary == NULL ? NULL : boundary->part;
+                                                msg_size, FALSE, has_nuls);
        }
+
+       return boundary == NULL ? NULL : boundary->part;
 }
 
 /* skip data until next boundary is found. if it's end boundary,
@@ -468,7 +503,7 @@ message_parse_body(struct istream *input, struct message_boundary *boundaries,
 static struct message_part *
 message_skip_boundary(struct istream *input,
                      struct message_boundary *boundaries,
-                     struct message_size *boundary_size)
+                     struct message_size *boundary_size, int *has_nuls)
 {
        struct message_boundary *boundary;
        const unsigned char *msg;
@@ -476,7 +511,7 @@ message_skip_boundary(struct istream *input,
        int end_boundary;
 
        boundary = message_find_boundary(input, boundaries,
-                                        boundary_size, TRUE);
+                                        boundary_size, TRUE, has_nuls);
        if (boundary == NULL)
                return NULL;
 
@@ -486,11 +521,12 @@ message_skip_boundary(struct istream *input,
                end_boundary = msg[0] == '-' && msg[1] == '-';
 
        /* skip the rest of the line */
-       message_skip_line(input, boundary_size, !end_boundary);
+       message_skip_line(input, boundary_size, !end_boundary, has_nuls);
 
        if (end_boundary) {
                /* skip the footer */
-               return message_parse_body(input, boundary->next, boundary_size);
+               return message_parse_body(input, boundary->next,
+                                         boundary_size, has_nuls);
        }
 
        return boundary == NULL ? NULL : boundary->part;
@@ -615,7 +651,7 @@ message_parse_header_next(struct message_header_parser_ctx *ctx)
                        if (colon_pos == UINT_MAX) {
                                /* header name is huge. just skip it. */
                                message_skip_line(ctx->input, ctx->hdr_size,
-                                                 TRUE);
+                                                 TRUE, &ctx->has_nuls);
                                continue;
                        }
 
@@ -645,14 +681,21 @@ message_parse_header_next(struct message_header_parser_ctx *ctx)
                                                /* end of headers, or error */
                                                break;
                                        }
+
+                                       if (msg[i] == '\0')
+                                               ctx->has_nuls = TRUE;
                                }
                        }
                }
 
                /* find '\n' */
                for (i = startpos; i < parse_size; i++) {
-                       if (msg[i] == '\n')
-                               break;
+                       if (msg[i] <= '\n') {
+                               if (msg[i] == '\n')
+                                       break;
+                               if (msg[i] == '\0')
+                                       ctx->has_nuls = TRUE;
+                       }
                }
 
                if (i < parse_size) {
index d68e0fc745a3436e59ccf9a9e033a21afeb69b01..3ccfa9becb23db6679c8f3d2fabf2ceb7927032f 100644 (file)
@@ -15,7 +15,10 @@ enum message_part_flags {
        MESSAGE_PART_FLAG_TEXT                  = 0x08,
 
        /* content-transfer-encoding: binary */
-       MESSAGE_PART_FLAG_BINARY                = 0x10
+       MESSAGE_PART_FLAG_BINARY                = 0x10,
+
+       /* message part header or body contains NULs */
+       MESSAGE_PART_FLAG_HAS_NULS              = 0x20
 };
 
 struct message_part {
index 2723ed1e9d3bbeaf86872d53765bd1f8ca5f64ac..95cfec2d0c67ba506e3616dce0acdc1f8cc38960 100644 (file)
@@ -9,13 +9,14 @@
 
 off_t message_send(struct ostream *output, struct istream *input,
                   const struct message_size *msg_size,
-                  uoff_t virtual_skip, uoff_t max_virtual_size, int *last_cr)
+                  uoff_t virtual_skip, uoff_t max_virtual_size, int *last_cr,
+                  int fix_nuls)
 {
        const unsigned char *msg;
        uoff_t old_limit, limit;
        size_t i, size;
        off_t ret;
-       int cr_skipped, add_cr;
+       int cr_skipped, add;
 
        if (last_cr != NULL)
                *last_cr = -1;
@@ -27,7 +28,7 @@ off_t message_send(struct ostream *output, struct istream *input,
        if (max_virtual_size > msg_size->virtual_size - virtual_skip)
                max_virtual_size = msg_size->virtual_size - virtual_skip;
 
-       if (msg_size->physical_size == msg_size->virtual_size) {
+       if (msg_size->physical_size == msg_size->virtual_size && !fix_nuls) {
                /* no need to kludge with CRs, we can use sendfile() */
                i_stream_skip(input, virtual_skip);
 
@@ -46,7 +47,7 @@ off_t message_send(struct ostream *output, struct istream *input,
        ret = 0;
        while (max_virtual_size > 0 &&
               i_stream_read_data(input, &msg, &size, 0) > 0) {
-               add_cr = FALSE;
+               add = '\0';
                for (i = 0; i < size && max_virtual_size > 0; i++) {
                        max_virtual_size--;
 
@@ -54,9 +55,12 @@ off_t message_send(struct ostream *output, struct istream *input,
                                if ((i == 0 && !cr_skipped) ||
                                    (i > 0 && msg[i-1] != '\r')) {
                                        /* missing CR */
-                                       add_cr = TRUE;
+                                       add = '\r';
                                        break;
                                }
+                       } else if (msg[i] == '\0') {
+                               add = 128;
+                               break;
                        }
                }
 
@@ -64,11 +68,12 @@ off_t message_send(struct ostream *output, struct istream *input,
                if (o_stream_send(output, msg, i) < 0)
                        return -1;
 
-               if (add_cr) {
+               if (add != '\0') {
                        ret++;
-                       if (o_stream_send(output, "\r", 1) < 0)
+                       if (o_stream_send(output, &add, 1) < 0)
                                return -1;
-                       cr_skipped = TRUE;
+                       cr_skipped = add == '\r';
+                       if (add == 128) i++;
                } else {
                        cr_skipped = i > 0 && msg[i-1] == '\r';
                }
index 1aec82bb1878b8cb15ed9a6c754fdef82acc6633..dc17f38a85a112ddaee5f0dee2cf1b255a6c8288 100644 (file)
@@ -10,7 +10,8 @@ struct message_size;
    known. Returns number of bytes sent, or -1 if error. */
 off_t message_send(struct ostream *output, struct istream *input,
                   const struct message_size *msg_size,
-                  uoff_t virtual_skip, uoff_t max_virtual_size, int *last_cr);
+                  uoff_t virtual_skip, uoff_t max_virtual_size, int *last_cr,
+                  int fix_nuls);
 
 /* Skip number of virtual bytes from putfer. msg_size is updated if it's not
    NULL. If cr_skipped is TRUE and first character is \n, it's not treated as
index 09229933c761409d54b094bf206b602a1a72239b..00c2766f74f5493ec9f80987355bc79c263a8f1f 100644 (file)
@@ -5,18 +5,24 @@
 #include "message-parser.h"
 #include "message-size.h"
 
-void message_get_header_size(struct istream *input, struct message_size *hdr)
+void message_get_header_size(struct istream *input, struct message_size *hdr,
+                            int *has_nuls)
 {
        const unsigned char *msg;
        size_t i, size, startpos, missing_cr_count;
 
        memset(hdr, 0, sizeof(struct message_size));
+       if (has_nuls != NULL)
+               *has_nuls = FALSE;
 
        missing_cr_count = 0; startpos = 0;
        while (i_stream_read_data(input, &msg, &size, startpos) > 0) {
                for (i = startpos; i < size; i++) {
-                       if (msg[i] != '\n')
+                       if (msg[i] != '\n') {
+                               if (msg[i] == '\0' && has_nuls != NULL)
+                                       *has_nuls = TRUE;
                                continue;
+                       }
 
                        hdr->lines++;
                        if (i == 0 || msg[i-1] != '\r') {
@@ -56,13 +62,15 @@ void message_get_header_size(struct istream *input, struct message_size *hdr)
 }
 
 void message_get_body_size(struct istream *input, struct message_size *body,
-                          uoff_t max_virtual_size, int *last_cr)
+                          uoff_t max_virtual_size, int *last_cr, int *has_nuls)
 {
        const unsigned char *msg;
        size_t i, size, startpos, missing_cr_count;
        int cr;
 
        memset(body, 0, sizeof(struct message_size));
+       if (has_nuls != NULL)
+               *has_nuls = FALSE;
 
        cr = 0;
        missing_cr_count = 0; startpos = 0;
@@ -72,7 +80,10 @@ void message_get_body_size(struct istream *input, struct message_size *body,
                for (i = startpos; i < size && max_virtual_size > 0; i++) {
                        max_virtual_size--;
 
-                       if (msg[i] == '\n') {
+                       if (msg[i] == '\0') {
+                               if (has_nuls != NULL)
+                                       *has_nuls = TRUE;
+                       } else if (msg[i] == '\n') {
                                if (i == 0 || msg[i-1] != '\r') {
                                        /* missing CR */
                                        missing_cr_count++;
index 0c180fb3e33912a4d46e61e5e5166b08801e74a5..8b559a65eced4b98130cff825704e5dce1c7ab07 100644 (file)
@@ -9,12 +9,14 @@ struct message_size {
 
 /* Calculate size of message header. Leave the input point to first
    character in body. */
-void message_get_header_size(struct istream *input, struct message_size *hdr);
+void message_get_header_size(struct istream *input, struct message_size *hdr,
+                            int *has_nuls);
 /* Calculate size of message body. Read only max_virtual_size virtual bytes,
    if you want it unlimited, use (uoff_t)-1. If last_cr is not NULL, it's set
    to 1 if last character is CR, 2 if it's virtual CR. */
 void message_get_body_size(struct istream *input, struct message_size *body,
-                          uoff_t max_virtual_size, int *last_cr);
+                          uoff_t max_virtual_size, int *last_cr,
+                          int *has_nuls);
 
 /* Sum contents of src into dest. */
 void message_size_add(struct message_size *dest,
index b23a00e905c4dadcbe87f21e64ce384b202e9f4d..3b56fd59086142fdeb02baf93cc499a93cfa70ae 100644 (file)
@@ -40,6 +40,15 @@ static struct message_part *get_cached_parts(struct index_mail *mail)
                return NULL;
        }
 
+       /* we know the NULs now, update them */
+       if ((part->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
+               mail->mail.has_nuls = TRUE;
+               mail->mail.has_no_nuls = FALSE;
+       } else {
+               mail->mail.has_nuls = FALSE;
+               mail->mail.has_no_nuls = TRUE;
+       }
+
        return part;
 }
 
@@ -261,6 +270,16 @@ static const struct message_part *get_parts(struct mail *_mail)
         index_mail_init_parse_header(mail);
        data->parts = message_parse(mail->pool, data->stream,
                                    index_mail_parse_header, mail);
+
+       /* we know the NULs now, update them */
+       if ((data->parts->flags & MESSAGE_PART_FLAG_HAS_NULS) != 0) {
+               _mail->has_nuls = TRUE;
+               _mail->has_no_nuls = FALSE;
+       } else {
+               _mail->has_nuls = FALSE;
+               _mail->has_no_nuls = TRUE;
+       }
+
        return data->parts;
 }
 
@@ -411,13 +430,13 @@ static uoff_t get_size(struct mail *_mail)
                return (uoff_t)-1;
 
        if (hdr_phys_size == (uoff_t)-1) {
-               message_get_header_size(data->stream, &data->hdr_size);
+               message_get_header_size(data->stream, &data->hdr_size, NULL);
                hdr_size = data->hdr_size.virtual_size;
                data->hdr_size_set = TRUE;
        }
        if (body_size == (uoff_t)-1) {
                message_get_body_size(data->stream, &data->body_size,
-                                     (uoff_t)-1, NULL);
+                                     (uoff_t)-1, NULL, NULL);
                body_size = data->body_size.virtual_size;
                data->body_size_set = TRUE;
        }
@@ -534,7 +553,8 @@ static struct istream *get_stream(struct mail *_mail,
 
        if (hdr_size != NULL) {
                if (!data->hdr_size_set) {
-                       message_get_header_size(data->stream, &data->hdr_size);
+                       message_get_header_size(data->stream, &data->hdr_size,
+                                               NULL);
                        data->hdr_size_set = TRUE;
                }
 
@@ -547,7 +567,7 @@ static struct istream *get_stream(struct mail *_mail,
                                      data->hdr_size.physical_size);
 
                        message_get_body_size(data->stream, &data->body_size,
-                                             (uoff_t)-1, NULL);
+                                             (uoff_t)-1, NULL, NULL);
                        data->body_size_set = TRUE;
                }
 
@@ -618,7 +638,7 @@ static const char *get_special(struct mail *_mail, enum mail_fetch_field field)
 }
 
 static struct mail index_mail = {
-       0, 0, 0,
+       0, 0, 0, 0, 0,
 
        get_flags,
        get_parts,
@@ -658,6 +678,11 @@ int index_mail_next(struct index_mail *mail, struct mail_index_record *rec)
        memset(data, 0, sizeof(*data));
        p_clear(mail->pool);
 
+       mail->mail.has_nuls =
+               (rec->index_flags & INDEX_MAIL_FLAG_HAS_NULS) != 0;
+       mail->mail.has_no_nuls =
+               (rec->index_flags & INDEX_MAIL_FLAG_HAS_NO_NULS) != 0;
+
        data->rec = rec;
        data->size = (uoff_t)-1;
        data->received_date = data->sent_time = (time_t)-1;
index b816d5398792a685752d862657275f2e936506c8..9c5382ba132da7af896ef9189cd71edd3fc73273 100644 (file)
@@ -337,6 +337,8 @@ struct mail {
        unsigned int uid;
 
        unsigned int seen_updated:1; /* if update_seen was TRUE */
+       unsigned int has_nuls:1; /* message data is known to contain NULs */
+       unsigned int has_no_nuls:1; /* -''- known to not contain NULs */
 
        const struct mail_full_flags *(*get_flags)(struct mail *mail);
        const struct message_part *(*get_parts)(struct mail *mail);