From: Timo Sirainen Date: Sat, 26 Apr 2003 21:52:38 +0000 (+0300) Subject: Partial fetches were broken when they stopped between virtual CR and LF. X-Git-Tag: 1.1.alpha1~4715 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=3ed5b60132508928e82d685d901ad3e6f95b0df0;p=thirdparty%2Fdovecot%2Fcore.git Partial fetches were broken when they stopped between virtual CR and LF. --HG-- branch : HEAD --- diff --git a/src/imap/imap-fetch-body-section.c b/src/imap/imap-fetch-body-section.c index c68702c6cb..97d365a5b5 100644 --- a/src/imap/imap-fetch-body-section.c +++ b/src/imap/imap-fetch-body-section.c @@ -34,10 +34,11 @@ struct partial_cache { unsigned int uid; uoff_t physical_start; + int cr_skipped; struct message_size pos; }; -static struct partial_cache partial = { 0, 0, 0, { 0, 0, 0 } }; +static struct partial_cache partial = { 0, 0, 0, 0, { 0, 0, 0 } }; static int seek_partial(unsigned int select_counter, unsigned int uid, struct partial_cache *partial, struct istream *stream, @@ -59,11 +60,10 @@ static int seek_partial(unsigned int select_counter, unsigned int uid, i_stream_seek(stream, partial->physical_start + partial->pos.physical_size); - message_skip_virtual(stream, virtual_skip, &partial->pos, &cr_skipped); - - if (cr_skipped) - partial->pos.virtual_size--; + message_skip_virtual(stream, virtual_skip, &partial->pos, + partial->cr_skipped, &cr_skipped); + partial->cr_skipped = FALSE; return cr_skipped; } @@ -75,7 +75,7 @@ static int fetch_body(struct imap_fetch_context *ctx, struct message_size hdr_size, body_size; struct istream *stream; const char *str; - int skip_cr; + int skip_cr, last_cr; uoff_t size; off_t ret; @@ -102,8 +102,9 @@ static int fetch_body(struct imap_fetch_context *ctx, body->skip); ret = message_send(ctx->output, stream, &body_size, - skip_cr, body->max_size); + skip_cr, body->max_size, &last_cr); if (ret > 0) { + partial.cr_skipped = last_cr != 0; partial.pos.physical_size = stream->v_offset - partial.physical_start; partial.pos.virtual_size += ret; @@ -287,7 +288,7 @@ 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) >= 0; + body->skip, body->max_size, NULL) >= 0; } /* partial headers - copy the wanted fields into memory, inserting @@ -418,7 +419,7 @@ static int fetch_part_body(struct imap_fetch_context *ctx, struct mail *mail, const struct message_part *part) { const char *str; - int skip_cr; + int skip_cr, last_cr; uoff_t size; off_t ret; @@ -436,8 +437,9 @@ 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); + skip_cr, body->max_size, &last_cr); if (ret > 0) { + partial.cr_skipped = last_cr != 0; partial.pos.physical_size = stream->v_offset - partial.physical_start; partial.pos.virtual_size += ret; diff --git a/src/imap/imap-fetch.c b/src/imap/imap-fetch.c index fa847aa236..66e61a656f 100644 --- a/src/imap/imap-fetch.c +++ b/src/imap/imap-fetch.c @@ -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) >= 0; + 0, (uoff_t)-1, NULL) >= 0; } static int fetch_send_rfc822_header(struct imap_fetch_context *ctx, @@ -135,7 +135,8 @@ static int fetch_send_rfc822_header(struct imap_fetch_context *ctx, if (o_stream_send_str(ctx->output, str) < 0) return FALSE; - return message_send(ctx->output, stream, &hdr_size, 0, (uoff_t)-1) >= 0; + return message_send(ctx->output, stream, &hdr_size, + 0, (uoff_t)-1, NULL) >= 0; } static int fetch_send_rfc822_text(struct imap_fetch_context *ctx, @@ -159,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) >= 0; + 0, (uoff_t)-1, NULL) >= 0; } static int fetch_mail(struct imap_fetch_context *ctx, struct mail *mail) diff --git a/src/lib-mail/message-send.c b/src/lib-mail/message-send.c index 0e4af83ec0..2723ed1e9d 100644 --- a/src/lib-mail/message-send.c +++ b/src/lib-mail/message-send.c @@ -9,7 +9,7 @@ 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) + uoff_t virtual_skip, uoff_t max_virtual_size, int *last_cr) { const unsigned char *msg; uoff_t old_limit, limit; @@ -17,6 +17,9 @@ off_t message_send(struct ostream *output, struct istream *input, off_t ret; int cr_skipped, add_cr; + if (last_cr != NULL) + *last_cr = -1; + if (msg_size->physical_size == 0 || virtual_skip >= msg_size->virtual_size) return 0; @@ -37,7 +40,7 @@ off_t message_send(struct ostream *output, struct istream *input, return ret; } - message_skip_virtual(input, virtual_skip, NULL, &cr_skipped); + message_skip_virtual(input, virtual_skip, NULL, 0, &cr_skipped); /* go through the message data and insert CRs where needed. */ ret = 0; @@ -73,5 +76,70 @@ off_t message_send(struct ostream *output, struct istream *input, i_stream_skip(input, i); } + if (last_cr != NULL) + *last_cr = cr_skipped; return ret; } + +void message_skip_virtual(struct istream *input, uoff_t virtual_skip, + struct message_size *msg_size, + int cr_skipped, int *last_cr) +{ + const unsigned char *msg; + size_t i, size, startpos; + + if (virtual_skip == 0) { + *last_cr = cr_skipped; + return; + } + + *last_cr = FALSE; + startpos = 0; + while (i_stream_read_data(input, &msg, &size, startpos) > 0) { + for (i = startpos; i < size && virtual_skip > 0; i++) { + virtual_skip--; + + if (msg[i] == '\r') { + /* CR */ + if (virtual_skip == 0) + *last_cr = TRUE; + } else if (msg[i] == '\n') { + /* LF */ + if ((i == 0 && !cr_skipped) || + (i > 0 && msg[i-1] != '\r')) { + /* missing CR */ + if (msg_size != NULL) + msg_size->virtual_size++; + + if (virtual_skip == 0) { + /* CR/LF boundary */ + *last_cr = TRUE; + break; + } + + virtual_skip--; + } + + /* increase after making sure we didn't break + at virtual \r */ + if (msg_size != NULL) + msg_size->lines++; + } + } + + if (msg_size != NULL) { + msg_size->physical_size += i; + msg_size->virtual_size += i; + } + + if (i < size) { + i_stream_skip(input, i); + break; + } + + /* leave the last character, it may be \r */ + i_stream_skip(input, i - 1); + startpos = 1; + cr_skipped = FALSE; + } +} diff --git a/src/lib-mail/message-send.h b/src/lib-mail/message-send.h index 942d8fd25f..1aec82bb18 100644 --- a/src/lib-mail/message-send.h +++ b/src/lib-mail/message-send.h @@ -6,10 +6,18 @@ struct message_size; /* Send message to client inserting CRs if needed. Only max_virtual_size bytes if sent (relative to virtual_skip), if you want it unlimited, use (uoff_t)-1. Remember that if input begins with LF, CR is inserted - before it unless virtual_skip = 1. Returns number of bytes sent, or -1 - if error. */ + before it unless virtual_skip = 1. last_cr is set to 1, 0 or -1 if not + 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); + uoff_t virtual_skip, uoff_t max_virtual_size, int *last_cr); + +/* 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 + \r\n. last_cr is set to TRUE if last character we skipped was \r, meaning + that next character should be \n and you shouldn't treat it as \r\n. */ +void message_skip_virtual(struct istream *input, uoff_t virtual_skip, + struct message_size *msg_size, + int cr_skipped, int *last_cr); #endif diff --git a/src/lib-mail/message-size.c b/src/lib-mail/message-size.c index 321a9b4cb4..09229933c7 100644 --- a/src/lib-mail/message-size.c +++ b/src/lib-mail/message-size.c @@ -110,64 +110,6 @@ void message_get_body_size(struct istream *input, struct message_size *body, *last_cr = cr; } -void message_skip_virtual(struct istream *input, uoff_t virtual_skip, - struct message_size *msg_size, int *cr_skipped) -{ - const unsigned char *msg; - size_t i, size, startpos; - - *cr_skipped = FALSE; - if (virtual_skip == 0) - return; - - startpos = 0; - while (i_stream_read_data(input, &msg, &size, startpos) > 0) { - for (i = startpos; i < size && virtual_skip > 0; i++) { - virtual_skip--; - - if (msg[i] == '\r') { - /* CR */ - if (virtual_skip == 0) - *cr_skipped = TRUE; - } else if (msg[i] == '\n') { - /* LF */ - if (i == 0 || msg[i-1] != '\r') { - /* missing CR */ - if (msg_size != NULL) - msg_size->virtual_size++; - - if (virtual_skip == 0) { - /* CR/LF boundary */ - *cr_skipped = TRUE; - break; - } - - virtual_skip--; - } - - /* increase after making sure we didn't break - at virtual \r */ - if (msg_size != NULL) - msg_size->lines++; - } - } - - if (msg_size != NULL) { - msg_size->physical_size += i; - msg_size->virtual_size += i; - } - - if (i < size) { - i_stream_skip(input, i); - break; - } - - /* leave the last character, it may be \r */ - i_stream_skip(input, i - 1); - startpos = 1; - } -} - void message_size_add(struct message_size *dest, const struct message_size *src) { diff --git a/src/lib-mail/message-size.h b/src/lib-mail/message-size.h index b8e2758a69..0c180fb3e3 100644 --- a/src/lib-mail/message-size.h +++ b/src/lib-mail/message-size.h @@ -16,12 +16,6 @@ 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); -/* Skip number of virtual bytes from putfer. If first character is \n, and - cr_skipped is FALSE, \r must be sent before it. msg_size is updated if - it's not NULL. */ -void message_skip_virtual(struct istream *input, uoff_t virtual_skip, - struct message_size *msg_size, int *cr_skipped); - /* Sum contents of src into dest. */ void message_size_add(struct message_size *dest, const struct message_size *src);