summaryrefslogtreecommitdiffstats
path: root/src/lib-mail/message-size.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 17:36:47 +0000
commit0441d265f2bb9da249c7abf333f0f771fadb4ab5 (patch)
tree3f3789daa2f6db22da6e55e92bee0062a7d613fe /src/lib-mail/message-size.c
parentInitial commit. (diff)
downloaddovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.tar.xz
dovecot-0441d265f2bb9da249c7abf333f0f771fadb4ab5.zip
Adding upstream version 1:2.3.21+dfsg1.upstream/1%2.3.21+dfsg1
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/lib-mail/message-size.c')
-rw-r--r--src/lib-mail/message-size.c174
1 files changed, 174 insertions, 0 deletions
diff --git a/src/lib-mail/message-size.c b/src/lib-mail/message-size.c
new file mode 100644
index 0000000..472abeb
--- /dev/null
+++ b/src/lib-mail/message-size.c
@@ -0,0 +1,174 @@
+/* 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;
+}