/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "istream.h" #include "message-parser.h" #include "message-size.h" int message_get_header_size(struct istream *input, struct message_size *hdr, bool *has_nuls_r) { const unsigned char *msg; size_t i, size, startpos, missing_cr_count; int ret; memset(hdr, 0, sizeof(struct message_size)); *has_nuls_r = FALSE; missing_cr_count = 0; startpos = 0; while ((ret = i_stream_read_bytes(input, &msg, &size, startpos + 1)) > 0) { for (i = startpos; i < size; i++) { if (msg[i] != '\n') { if (msg[i] == '\0') *has_nuls_r = TRUE; continue; } hdr->lines++; if (i == 0 || msg[i-1] != '\r') { /* missing CR */ missing_cr_count++; } if (i == 0 || (i == 1 && msg[i-1] == '\r')) { /* no headers at all */ break; } if ((i > 0 && msg[i-1] == '\n') || (i > 1 && msg[i-2] == '\n' && msg[i-1] == '\r')) { /* \n\n or \n\r\n - end of headers */ break; } } if (i < size) { /* end of header */ startpos = i+1; break; } /* leave the last two characters, they may be \r\n */ startpos = size == 1 ? 1 : 2; i_stream_skip(input, i - startpos); hdr->physical_size += i - startpos; } i_assert(ret == -1 || ret > 0); ret = input->stream_errno != 0 ? -1 : 0; i_stream_skip(input, startpos); hdr->physical_size += startpos; hdr->virtual_size = hdr->physical_size + missing_cr_count; i_assert(hdr->virtual_size >= hdr->physical_size); return ret; } int message_get_body_size(struct istream *input, struct message_size *body, bool *has_nuls_r) { const unsigned char *msg; size_t i, size, missing_cr_count; int ret; memset(body, 0, sizeof(struct message_size)); *has_nuls_r = FALSE; missing_cr_count = 0; if ((ret = i_stream_read_more(input, &msg, &size)) <= 0) { i_assert(ret == -1); return ret < 0 && input->stream_errno != 0 ? -1 : 0; } if (msg[0] == '\n') missing_cr_count++; do { for (i = 1; i < size; i++) { if (msg[i] > '\n') continue; if (msg[i] == '\n') { if (msg[i-1] != '\r') { /* missing CR */ missing_cr_count++; } /* increase after making sure we didn't break at virtual \r */ body->lines++; } else if (msg[i] == '\0') { *has_nuls_r = TRUE; } } /* leave the last character, it may be \r */ i_stream_skip(input, i - 1); body->physical_size += i - 1; } while ((ret = i_stream_read_bytes(input, &msg, &size, 2)) > 0); i_assert(ret == -1); ret = input->stream_errno != 0 ? -1 : 0; i_stream_skip(input, 1); body->physical_size++; body->virtual_size = body->physical_size + missing_cr_count; i_assert(body->virtual_size >= body->physical_size); return ret; } void message_size_add(struct message_size *dest, const struct message_size *src) { dest->virtual_size += src->virtual_size; dest->physical_size += src->physical_size; dest->lines += src->lines; } int message_skip_virtual(struct istream *input, uoff_t virtual_skip, bool *last_cr_r) { const unsigned char *msg; size_t i, size; bool cr_skipped = FALSE; int ret; *last_cr_r = FALSE; if (virtual_skip == 0) return 0; while ((ret = i_stream_read_more(input, &msg, &size)) > 0) { for (i = 0; i < size && virtual_skip > 0; i++) { virtual_skip--; if (msg[i] == '\r') { /* CR */ if (virtual_skip == 0) *last_cr_r = TRUE; } else if (msg[i] == '\n') { /* LF */ if ((i == 0 && !cr_skipped) || (i > 0 && msg[i-1] != '\r')) { if (virtual_skip == 0) { /* CR/LF boundary */ *last_cr_r = TRUE; break; } virtual_skip--; } } } i_stream_skip(input, i); if (i < size) return 0; i_assert(i > 0); cr_skipped = msg[i-1] == '\r'; } i_assert(ret == -1); return input->stream_errno == 0 ? 0 : -1; }