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,
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;
}
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;
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;
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
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;
&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;
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,
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,
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)
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;
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;
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;
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;
+ }
+}
/* 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
*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)
{
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);