message-size.c revision 2a5404c1f5726b0912f4ec7dc763262f2aabd2d7
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen#include "lib.h"
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen#include "istream.h"
ee6df9526e9716b3f1734d85b566e00fc41208bcTimo Sirainen#include "message-parser.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen#include "message-size.h"
e76073ebaf90fa29abfdc364873acf78983949aaTimo Sirainen
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainenint message_get_header_size(struct istream *input, struct message_size *hdr,
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen bool *has_nuls)
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen{
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen const unsigned char *msg;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen size_t i, size, startpos, missing_cr_count;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen int ret;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen memset(hdr, 0, sizeof(struct message_size));
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen if (has_nuls != NULL)
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen *has_nuls = FALSE;
0f39a57760d93cddbce3ca43096d78e0fe2f42fdTimo Sirainen
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen missing_cr_count = 0; startpos = 0;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen while (i_stream_read_data(input, &msg, &size, startpos) > 0) {
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen for (i = startpos; i < size; i++) {
22535a9e685e29214082878e37a267157044618eTimo Sirainen if (msg[i] != '\n') {
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if (msg[i] == '\0' && has_nuls != NULL)
f3d506e525a720f214020ca0f989a1966b30edaeTimo Sirainen *has_nuls = TRUE;
74674a53a72dab535c61f455b2246ef2797844eaTimo Sirainen continue;
74674a53a72dab535c61f455b2246ef2797844eaTimo Sirainen }
74674a53a72dab535c61f455b2246ef2797844eaTimo Sirainen
74674a53a72dab535c61f455b2246ef2797844eaTimo Sirainen hdr->lines++;
c5383a0ed56a188a7d5efaaa4c6f8243af432d65Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* missing CR */
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen missing_cr_count++;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen }
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen
3cf67672fdc87583cb23ce088c95bb5dee60e74dTimo Sirainen if (i == 0 || (i == 1 && msg[i-1] == '\r')) {
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen /* no headers at all */
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen break;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen }
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen
2d8f66596f445dd8b399b7032c3f0e9202015b63Timo Sirainen if ((i > 0 && msg[i-1] == '\n') ||
2d8f66596f445dd8b399b7032c3f0e9202015b63Timo Sirainen (i > 1 && msg[i-2] == '\n' && msg[i-1] == '\r')) {
2d8f66596f445dd8b399b7032c3f0e9202015b63Timo Sirainen /* \n\n or \n\r\n - end of headers */
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen break;
9ed2951bd0bb1878a27437d7c00611b2baadd614Timo Sirainen }
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen }
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen if (i < size) {
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen /* end of header */
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen startpos = i+1;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen break;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen }
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen /* leave the last two characters, they may be \r\n */
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen startpos = size == 1 ? 1 : 2;
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen i_stream_skip(input, i - startpos);
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen hdr->physical_size += i - startpos;
f3d506e525a720f214020ca0f989a1966b30edaeTimo Sirainen }
b42f37ae6f65ed986315b6885568d32115e589b1Timo Sirainen ret = input->stream_errno != 0 ? -1 : 0;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen i_stream_skip(input, startpos);
3b94ff5951db4d4eddb7a80ed4e3f61207202635Timo Sirainen hdr->physical_size += startpos;
66d2db642fe24d555d113ba463e446b038d476efTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen hdr->virtual_size = hdr->physical_size + missing_cr_count;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen i_assert(hdr->virtual_size >= hdr->physical_size);
e9371f899a3d4207a0ffd3923ea5ec7250cf5e75Timo Sirainen return ret;
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen}
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainenint message_get_body_size(struct istream *input, struct message_size *body,
43d3ea2780b5f8557ede7b4c039e8f56cb8d357dTimo Sirainen bool *has_nuls)
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen{
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen const unsigned char *msg;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen size_t i, size, missing_cr_count;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen bool last_cr;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen int ret;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
12aad74464367f7e8be11eafe1af985bf7b1adecTimo Sirainen memset(body, 0, sizeof(struct message_size));
e48d89622047bd8bbd0475b881ca9377d592f535Timo Sirainen if (has_nuls != NULL)
04052d7cacaa866a3f00afb4e104fa46c04c1dd7Timo Sirainen *has_nuls = FALSE;
f3d506e525a720f214020ca0f989a1966b30edaeTimo Sirainen
849969f639a00eab26791db3cb1b66430420c0cdTimo Sirainen missing_cr_count = 0; last_cr = FALSE;
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen if ((ret = i_stream_read_data(input, &msg, &size, 0)) <= 0)
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen return ret < 0 && input->stream_errno != 0 ? -1 : 0;
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen if (msg[0] == '\n')
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen missing_cr_count++;
be5c76fabc7439fd33bc799bc3ab3f570799977bTimo Sirainen
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen do {
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen for (i = 1; i < size; i++) {
43a66a0b16299bd4f7615acd85e98bd3832c54d5Timo Sirainen if (msg[i] > '\n')
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen continue;
1e21e6be70994b1aa9e52ca0e2f51afefca6d0dfTimo Sirainen
25757faf029c369a8318349dafe952e2358df1d8Timo Sirainen 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') {
if (has_nuls != NULL)
*has_nuls = TRUE;
}
}
/* leave the last character, it may be \r */
i_stream_skip(input, i - 1);
body->physical_size += i - 1;
} while (i_stream_read_data(input, &msg, &size, 1) > 0);
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;
}