From: Timo Sirainen Date: Sat, 8 Nov 2003 21:12:45 +0000 (+0200) Subject: cleanups and fix for partial header fetching X-Git-Tag: 1.1.alpha1~4238 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=9614cdaf3bbbf178601130eac2a5b396fbc34711;p=thirdparty%2Fdovecot%2Fcore.git cleanups and fix for partial header fetching --HG-- branch : HEAD --- diff --git a/src/imap/imap-fetch-body-section.c b/src/imap/imap-fetch-body-section.c index fd021877ef..a466738f53 100644 --- a/src/imap/imap-fetch-body-section.c +++ b/src/imap/imap-fetch-body-section.c @@ -85,45 +85,72 @@ static uoff_t get_send_size(const struct imap_fetch_body_data *body, return size <= body->max_size ? size : body->max_size; } -/* fetch BODY[] or BODY[TEXT] */ -static int fetch_body(struct imap_fetch_context *ctx, +static int fetch_data(struct imap_fetch_context *ctx, const struct imap_fetch_body_data *body, - struct mail *mail, int fetch_header) + struct mail *mail, struct istream *input, + uoff_t physical_start, const struct message_size *size) { - struct message_size hdr_size, body_size; - struct istream *stream; const char *str; - int skip_cr, last_cr; uoff_t send_size; off_t ret; + int skip_cr, last_cr; - stream = mail->get_stream(mail, &hdr_size, &body_size); - if (stream == NULL) - return FALSE; - - if (fetch_header) - message_size_add(&body_size, &hdr_size); + send_size = get_send_size(body, size->virtual_size); - send_size = get_send_size(body, body_size.virtual_size); str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", ctx->prefix, send_size); if (o_stream_send_str(ctx->output, str) < 0) return FALSE; skip_cr = seek_partial(ctx->select_counter, mail->uid, - &partial, stream, - fetch_header ? 0 : hdr_size.physical_size, - body->skip); + &partial, input, physical_start, body->skip); - ret = message_send(ctx->output, stream, &body_size, - skip_cr, send_size, &last_cr, - !mail->has_no_nuls); + ret = message_send(ctx->output, input, size, skip_cr, send_size, + &last_cr, !mail->has_no_nuls); if (ret > 0) { partial.cr_skipped = last_cr != 0; partial.pos.physical_size = - stream->v_offset - partial.physical_start; + input->v_offset - partial.physical_start; partial.pos.virtual_size += ret; } - return ret >= 0; + + if (ret != (off_t)send_size) { + /* Input stream gave less data then we expected. Two choices + here: either we fill the missing data with spaces or we + disconnect the client. + + We shouldn't really ever get here. One reason is if mail + was deleted from NFS server while we were reading it. + Another is some temporary disk error. + + If we filled the missing data the client could cache it, + and if it was just a temporary error the message would be + permanently left corrupted in client's local cache. So, we + disconnect the client and hope that next try works. */ + o_stream_close(ctx->output); + return FALSE; + } + + return TRUE; +} + +/* fetch BODY[] or BODY[TEXT] */ +static int fetch_body(struct imap_fetch_context *ctx, + const struct imap_fetch_body_data *body, + struct mail *mail, int fetch_header) +{ + struct message_size hdr_size, body_size; + struct istream *stream; + + stream = mail->get_stream(mail, &hdr_size, &body_size); + if (stream == NULL) + return FALSE; + + if (fetch_header) + message_size_add(&body_size, &hdr_size); + + return fetch_data(ctx, body, mail, stream, + fetch_header ? 0 : hdr_size.physical_size, + &body_size); } static int header_match(const char *const *fields, @@ -304,25 +331,14 @@ static int fetch_header_from(struct imap_fetch_context *ctx, const char *str; const void *data; size_t data_size; - uoff_t start_offset, send_size; - int failed, skip_cr; + uoff_t start_offset; + int failed; /* HEADER, MIME, HEADER.FIELDS (list), HEADER.FIELDS.NOT (list) */ if (strcmp(header_section, "HEADER") == 0) { /* all headers */ - send_size = get_send_size(body, size->virtual_size); - str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", - ctx->prefix, send_size); - if (o_stream_send_str(ctx->output, str) < 0) - return FALSE; - - skip_cr = seek_partial(ctx->select_counter, mail->uid, - &partial, input, 0, body->skip); - - return message_send(ctx->output, input, size, - skip_cr, send_size, NULL, - !mail->has_no_nuls) >= 0; + return fetch_data(ctx, body, mail, input, 0, size); } /* partial headers - copy the wanted fields into memory, inserting @@ -457,36 +473,6 @@ static int part_find(struct mail *mail, const struct imap_fetch_body_data *body, return TRUE; } -/* fetch BODY[1.2] or BODY[1.2.TEXT] */ -static int fetch_part_body(struct imap_fetch_context *ctx, - struct istream *stream, - const struct imap_fetch_body_data *body, - struct mail *mail, const struct message_part *part) -{ - const char *str; - int skip_cr, last_cr; - uoff_t send_size; - off_t ret; - - send_size = get_send_size(body, part->body_size.virtual_size); - str = t_strdup_printf("%s {%"PRIuUOFF_T"}\r\n", ctx->prefix, send_size); - if (o_stream_send_str(ctx->output, str) < 0) - return FALSE; - - skip_cr = seek_partial(ctx->select_counter, mail->uid, - &partial, stream, part->physical_pos + - part->header_size.physical_size, body->skip); - ret = message_send(ctx->output, stream, &part->body_size, - skip_cr, send_size, &last_cr, !mail->has_no_nuls); - if (ret > 0) { - partial.cr_skipped = last_cr != 0; - partial.pos.physical_size = - stream->v_offset - partial.physical_start; - partial.pos.virtual_size += ret; - } - return ret >= 0; -} - static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail, const struct imap_fetch_body_data *body) { @@ -507,8 +493,12 @@ static int fetch_part(struct imap_fetch_context *ctx, struct mail *mail, if (stream == NULL) return FALSE; - if (*section == '\0' || strcmp(section, "TEXT") == 0) - return fetch_part_body(ctx, stream, body, mail, part); + if (*section == '\0' || strcmp(section, "TEXT") == 0) { + return fetch_data(ctx, body, mail, stream, + part->physical_pos + + part->header_size.physical_size, + &part->body_size); + } if (strncmp(section, "HEADER", 6) == 0 || strcmp(section, "MIME") == 0) {