message-send.c revision 6449bd276af37b3e0b81a9c47ecd01f39a2cba53
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2002 Timo Sirainen */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "lib.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "istream.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "ostream.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "message-parser.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen#include "message-send.h"
16f816d3f3c32ae3351834253f52ddd0212bcbf3Timo Sirainen#include "message-size.h"
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenoff_t message_send(struct ostream *output, struct istream *input,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const struct message_size *msg_size,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen uoff_t virtual_skip, uoff_t max_virtual_size, int *last_cr,
e156adefc1260d31a145df2f5e9b3c82050d4163Timo Sirainen int fix_nuls)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen const unsigned char *msg;
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen uoff_t old_limit, limit;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen size_t i, size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen off_t ret;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen int cr_skipped;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen unsigned char add;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (last_cr != NULL)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *last_cr = -1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen if (msg_size->physical_size == 0 ||
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen virtual_skip >= msg_size->virtual_size)
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen return 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (max_virtual_size > msg_size->virtual_size - virtual_skip)
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen max_virtual_size = msg_size->virtual_size - virtual_skip;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (msg_size->physical_size == msg_size->virtual_size && !fix_nuls) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* no need to kludge with CRs, we can use sendfile() */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen i_stream_skip(input, virtual_skip);
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen old_limit = input->v_limit;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen limit = input->v_offset + max_virtual_size;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_set_read_limit(input, I_MIN(limit, old_limit));
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen ret = o_stream_send_istream(output, input);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_set_read_limit(input, old_limit);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen return ret;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen message_skip_virtual(input, virtual_skip, NULL, 0, &cr_skipped);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* go through the message data and insert CRs where needed. */
8d80659e504ffb34bb0c6a633184fece35751b18Timo Sirainen ret = 0;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen while (max_virtual_size > 0 &&
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_read_data(input, &msg, &size, 0) > 0) {
785d9cca224d33ca3938e9166784f6483e8a27d7Timo Sirainen add = '\0';
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (i = 0; i < size && max_virtual_size > 0; i++) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen max_virtual_size--;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (msg[i] == '\n') {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if ((i == 0 && !cr_skipped) ||
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (i > 0 && msg[i-1] != '\r')) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen /* missing CR */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen add = '\r';
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen break;
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen }
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen } else if (msg[i] == '\0') {
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen add = 128;
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen break;
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen }
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen }
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen ret += i;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen if (o_stream_send(output, msg, i) < 0)
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen return -1;
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen if (add != '\0') {
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen ret++;
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen if (o_stream_send(output, &add, 1) < 0)
0449e50c99f3fab4485f9b983e3936aaa003c79aTimo Sirainen return -1;
91dca97b367c54a139c268b56a0c67f564bd9197Timo Sirainen cr_skipped = add == '\r';
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen if (add == 128) i++;
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen } else {
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen cr_skipped = i > 0 && msg[i-1] == '\r';
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
8da095519878426b012058e6f331a669f327f47fTimo Sirainen
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen i_stream_skip(input, i);
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen }
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen
036626b19f14bef582f96e556913ae91b1d67881Timo Sirainen if (last_cr != NULL)
6e1e9e341ffe21a69a23229c2b896d03066a071eTimo Sirainen *last_cr = cr_skipped;
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen return ret;
2615df45a8027948a474abe5e817b34b0499c171Timo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainenvoid message_skip_virtual(struct istream *input, uoff_t virtual_skip,
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen struct message_size *msg_size,
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen int cr_skipped, int *last_cr)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen{
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen const unsigned char *msg;
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen size_t i, size, startpos;
9740d55b228a670047c854484d5cc979a056a9afTimo Sirainen
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen if (virtual_skip == 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *last_cr = cr_skipped;
648d24583c1574441c4fa0331a90bd4d6e7996c5Timo Sirainen return;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *last_cr = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen startpos = 0;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen while (i_stream_read_data(input, &msg, &size, startpos) > 0) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen for (i = startpos; i < size && virtual_skip > 0; i++) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen virtual_skip--;
3ccab0bac68040f179a7de45c516cec258e28fdbTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (msg[i] == '\r') {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* CR */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (virtual_skip == 0)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen *last_cr = TRUE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen } else if (msg[i] == '\n') {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* LF */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if ((i == 0 && !cr_skipped) ||
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen (i > 0 && msg[i-1] != '\r')) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* missing CR */
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen if (msg_size != NULL)
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen msg_size->virtual_size++;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen if (virtual_skip == 0) {
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen /* CR/LF boundary */
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen *last_cr = TRUE;
1e47cfede3a0b62654105daab00e97b5d660bc6bTimo Sirainen break;
a64adf62fa33f2463a86f990217b0c9078531a40Timo Sirainen }
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen virtual_skip--;
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen }
04b8a90af181cc4c7959266855e8ed50a22ed413Timo Sirainen
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen /* increase after making sure we didn't break
181c1aff950e6f8e0556f8974e79d0747845ac0fTimo Sirainen at virtual \r */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (msg_size != NULL)
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen msg_size->lines++;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
0ea17cea21df405e6e74a167d08e1ff0ee95dd13Timo Sirainen if (msg_size != NULL) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen msg_size->physical_size += i;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen msg_size->virtual_size += i;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen if (i < size) {
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_skip(input, i);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen break;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen /* leave the last character, it may be \r */
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen i_stream_skip(input, i - 1);
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen startpos = 1;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen cr_skipped = FALSE;
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen }
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen}
cce169a321c9c629e4f2db1a69dae3b75bbcb27aTimo Sirainen