istream-raw-mbox.c revision 7f773564b94e6054a40d3785cb63c29f1e4d4dee
5e0ce63bb65db34d7f48b34bbb5545fa791781c4Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen#include "lib.h"
5254d77805cd35b9356d072ba325c356c43b0d51Timo Sirainen#include "buffer.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "istream-internal.h"
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen#include "istream-raw-mbox.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen#include "mbox-from.h"
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstruct raw_mbox_istream {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct _istream istream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen time_t received_time, next_received_time;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen char *sender, *next_sender;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen uoff_t from_offset, hdr_offset, body_offset, mail_size;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen struct istream *input;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen uoff_t input_peak_offset;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int corrupted:1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int eom:1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen unsigned int next_eof:1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen};
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void _close(struct _iostream *stream __attr_unused__)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainenstatic void _destroy(struct _iostream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen i_stream_seek(rstream->input, rstream->istream.istream.v_offset);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_unref(rstream->input);
2c25e1360d4b5cc55eda969a3a7204d950de5a8fTimo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_set_max_buffer_size(rstream->input, max_size);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic void _set_blocking(struct _iostream *stream, int timeout_msecs,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen void (*timeout_cb)(void *), void *context)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_set_blocking(rstream->input, timeout_msecs,
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen timeout_cb, context);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen}
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic int mbox_read_from_line(struct raw_mbox_istream *rstream)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen{
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen const unsigned char *buf, *p;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen char *sender;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen time_t received_time;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen size_t pos, line_pos;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen int skip;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen buf = i_stream_get_data(rstream->input, &pos);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_assert(pos > 0);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* from_offset points to "\nFrom ", so unless we're at the beginning
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen of the file, skip the initial \n */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen skip = rstream->from_offset != 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen while ((p = memchr(buf+skip, '\n', pos-skip)) == NULL) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen if (i_stream_read(rstream->input) < 0) {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen /* EOF - shouldn't happen */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen buf = i_stream_get_data(rstream->input, &pos);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen line_pos = (size_t)(p - buf);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (rstream->from_offset != 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen buf++;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen pos--;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* beginning of mbox */
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (memcmp(buf, "From ", 5) != 0 ||
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen mbox_from_parse(buf+5, pos-5, &received_time, &sender) < 0) {
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen /* broken From - should happen only at beginning of
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen file if this isn't a mbox.. */
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen return -1;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen }
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen if (rstream->istream.istream.v_offset == rstream->from_offset) {
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen rstream->received_time = received_time;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen i_free(rstream->sender);
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen rstream->sender = sender;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen } else {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen rstream->next_received_time = received_time;
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen i_free(rstream->next_sender);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen rstream->next_sender = sender;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* we'll skip over From-line */
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen rstream->istream.istream.v_offset += line_pos+1;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen i_stream_skip(rstream->input, line_pos+1);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen rstream->hdr_offset = rstream->istream.istream.v_offset;
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen return 0;
9e095dd6a77097356aca8216356d4d71ef1bea45Timo Sirainen}
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainenstatic ssize_t _read(struct _istream *stream)
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen{
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen static const char *mbox_from = "\nFrom ";
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const unsigned char *buf;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen const char *fromp;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen char *sender, eoh_char;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen time_t received_time;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen size_t i, pos, new_pos, from_start_pos;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen ssize_t ret = 0;
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (rstream->eom) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen if (rstream->body_offset == (uoff_t)-1) {
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen /* missing \n from headers */
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen rstream->body_offset =
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen stream->istream.v_offset +
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen (stream->pos - stream->skip);
2767104d81e97a109f0aa9758792bfa1da325a97Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->istream.eof = rstream->next_eof;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen return -1;
1060afdc2fcdf647dbb3bc11647401f1b44a3a8aTimo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen i_stream_seek(rstream->input, stream->istream.v_offset);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
602a0434db30d8e3292d1c161a803d96a879a74fTimo Sirainen stream->pos -= stream->skip;
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen stream->skip = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen stream->buffer = NULL;
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen do {
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen ret = i_stream_read(rstream->input);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen buf = i_stream_get_data(rstream->input, &pos);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen } while (ret > 0 &&
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen stream->istream.v_offset + pos <= rstream->input_peak_offset);
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen if (ret < 0) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (ret == -2)
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen return -2;
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen /* we've read the whole file, final byte should be
143cb2e0744e647f8fc637bbdea1106c1587a4bfTimo Sirainen the \n trailer */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (pos > 0 && buf[pos-1] == '\n')
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen pos--;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen i_assert(pos >= stream->pos);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen ret = pos == stream->pos ? -1 :
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen (ssize_t)(pos - stream->pos);
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen stream->buffer = buf;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen stream->pos = pos;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen rstream->eom = TRUE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen rstream->next_eof = TRUE;
7d207b1e77a7b5e3fda640e353acfc86d261fedfTimo Sirainen rstream->mail_size = stream->istream.v_offset + pos -
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen rstream->hdr_offset;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return ret < 0 ? _read(stream) : ret;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (stream->istream.v_offset == rstream->from_offset) {
cd1eef2109b4476842b7757f1d69b104196d5941Timo Sirainen /* beginning of message, we haven't yet read our From-line */
cd1eef2109b4476842b7757f1d69b104196d5941Timo Sirainen if (mbox_read_from_line(rstream) < 0) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen stream->pos = 0;
cd1eef2109b4476842b7757f1d69b104196d5941Timo Sirainen stream->istream.eof = TRUE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen rstream->corrupted = TRUE;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen return -1;
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen }
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* got it. we don't want to return it however,
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen so start again from headers */
6ef7e31619edfaa17ed044b45861d106a86191efTimo Sirainen buf = i_stream_get_data(rstream->input, &pos);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (pos == 0)
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen return _read(stream);
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen
c0435c854a0e7246373b9752d163095cc4fbe985Timo Sirainen /* See if we have From-line here - note that it works right only
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen because all characters are different in mbox_from. */
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen fromp = mbox_from; from_start_pos = 0;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen eoh_char = rstream->body_offset == (uoff_t)-1 ? '\n' : '\0';
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen for (i = 0; i < pos; i++) {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen if (buf[i] == eoh_char && i > 0 && buf[i-1] == '\n') {
7ef5ca6fb59a318c821a852ae48a2edbb671d7ddTimo Sirainen rstream->body_offset = stream->istream.v_offset + i + 1;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen eoh_char = '\0';
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen }
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (buf[i] == *fromp) {
07e4875d250e7a7157cd99132aafc773cf3cdf83Timo Sirainen if (*++fromp == '\0') {
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen /* potential From-line, see if we have the
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen rest of the line buffered.
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen FIXME: if From-line is longer than input
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen buffer, we break. probably irrelevant.. */
c06f4017027263cf3a08becc551f5126409e2a83Timo Sirainen i++;
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen from_start_pos = i;
411d6baa37f31d90730e90c4a28c43e1974bbe58Timo Sirainen fromp = mbox_from;
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen } else if (from_start_pos != 0) {
dd62b77c932d1b518f2a3e4bf80e36542becc256Timo Sirainen /* we have the whole From-line here now.
ecc81625167ed96c04c02aa190a1ea5baa65b474Timo Sirainen See if it's a valid one. */
if (mbox_from_parse(buf + from_start_pos,
pos - from_start_pos,
&received_time,
&sender) == 0) {
/* yep, we stop here. */
rstream->next_received_time =
received_time;
i_free(rstream->next_sender);
rstream->next_sender = sender;
rstream->eom = TRUE;
/* rewind "\nFrom " */
from_start_pos -= 6;
rstream->mail_size =
stream->istream.v_offset +
from_start_pos -
rstream->hdr_offset;
break;
}
from_start_pos = 0;
}
} else {
fromp = mbox_from;
if (buf[i] == *fromp)
fromp++;
}
}
/* we want to go at least one byte further next time */
rstream->input_peak_offset = stream->istream.v_offset + i;
if (from_start_pos != 0) {
/* we're waiting for the \n at the end of From-line */
new_pos = from_start_pos;
} else {
/* leave out the beginnings of potential From-line */
new_pos = i - (fromp - mbox_from);
}
i_assert(new_pos > stream->pos);
ret = new_pos - stream->pos;
stream->buffer = buf;
stream->pos = new_pos;
return ret;
}
static void _seek(struct _istream *stream, uoff_t v_offset)
{
struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
stream->istream.v_offset = v_offset;
stream->skip = stream->pos = 0;
stream->buffer = NULL;
rstream->input_peak_offset = 0;
rstream->eom = FALSE;
rstream->next_eof = FALSE;
}
struct istream *i_stream_create_raw_mbox(pool_t pool, struct istream *input)
{
struct raw_mbox_istream *rstream;
i_stream_ref(input);
rstream = p_new(pool, struct raw_mbox_istream, 1);
rstream->input = input;
rstream->body_offset = (uoff_t)-1;
rstream->mail_size = (uoff_t)-1;
rstream->received_time = (time_t)-1;
rstream->next_received_time = (time_t)-1;
rstream->istream.iostream.close = _close;
rstream->istream.iostream.destroy = _destroy;
rstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
rstream->istream.iostream.set_blocking = _set_blocking;
rstream->istream.read = _read;
rstream->istream.seek = _seek;
return _i_stream_create(&rstream->istream, pool, -1,
input->real_stream->abs_start_offset);
}
static int istream_raw_mbox_is_valid_from(struct raw_mbox_istream *rstream)
{
const unsigned char *data;
size_t size;
time_t received_time;
char *sender;
/* minimal: "From x Thu Nov 29 22:33:52 2001" = 31 chars */
if (i_stream_read_data(rstream->input, &data, &size, 30) == -1)
return -1;
if (size == 1 && data[0] == '\n') {
/* EOF */
return TRUE;
}
if (size < 31 || memcmp(data, "\nFrom ", 6) != 0)
return FALSE;
while (memchr(data+1, '\n', size-1) == NULL) {
if (i_stream_read_data(rstream->input, &data, &size, size) < 0)
break;
}
if (mbox_from_parse(data+6, size-6, &received_time, &sender) < 0)
return FALSE;
rstream->next_received_time = received_time;
i_free(rstream->next_sender);
rstream->next_sender = sender;
return TRUE;
}
uoff_t istream_raw_mbox_get_start_offset(struct istream *stream)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
return rstream->from_offset;
}
uoff_t istream_raw_mbox_get_header_offset(struct istream *stream)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
if (rstream->hdr_offset == rstream->from_offset)
(void)_read(&rstream->istream);
return rstream->hdr_offset;
}
uoff_t istream_raw_mbox_get_body_offset(struct istream *stream)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
uoff_t offset;
size_t pos;
if (rstream->body_offset != (uoff_t)-1)
return rstream->body_offset;
offset = stream->v_offset;
i_stream_seek(stream, rstream->hdr_offset);
while (rstream->body_offset == (uoff_t)-1) {
i_stream_get_data(stream, &pos);
i_stream_skip(stream, pos);
if (_read(&rstream->istream) < 0)
break;
}
i_stream_seek(stream, offset);
return rstream->body_offset;
}
uoff_t istream_raw_mbox_get_body_size(struct istream *stream, uoff_t body_size)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
const unsigned char *data;
size_t size;
i_assert(rstream->hdr_offset != (uoff_t)-1);
i_assert(rstream->body_offset != (uoff_t)-1);
if (rstream->mail_size != (uoff_t)-1) {
return rstream->mail_size -
(rstream->body_offset - rstream->hdr_offset);
}
if (body_size != (uoff_t)-1) {
i_stream_seek(rstream->input, rstream->body_offset + body_size);
if (istream_raw_mbox_is_valid_from(rstream) > 0) {
rstream->mail_size = body_size +
(rstream->body_offset - rstream->hdr_offset);
return body_size;
}
}
/* have to read through the message body */
while (i_stream_read_data(stream, &data, &size, 0) > 0)
i_stream_skip(stream, size);
i_assert(rstream->mail_size != (uoff_t)-1);
return rstream->mail_size -
(rstream->body_offset - rstream->hdr_offset);
}
time_t istream_raw_mbox_get_received_time(struct istream *stream)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
if (rstream->received_time == (time_t)-1)
(void)_read(&rstream->istream);
return rstream->received_time;
}
const char *istream_raw_mbox_get_sender(struct istream *stream)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
if (rstream->sender == NULL)
(void)_read(&rstream->istream);
return rstream->sender == NULL ? "" : rstream->sender;
}
void istream_raw_mbox_next(struct istream *stream, uoff_t body_size)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
body_size = istream_raw_mbox_get_body_size(stream, body_size);
rstream->mail_size = (uoff_t)-1;
rstream->received_time = rstream->next_received_time;
rstream->next_received_time = (time_t)-1;
i_free(rstream->sender);
rstream->sender = rstream->next_sender;
rstream->next_sender = NULL;
rstream->from_offset = rstream->body_offset + body_size;
rstream->hdr_offset = rstream->from_offset;
rstream->body_offset = (uoff_t)-1;
/* don't clear stream->eof if we don't have to */
if (stream->v_offset != rstream->from_offset)
i_stream_seek(stream, rstream->from_offset);
i_stream_seek(rstream->input, rstream->from_offset);
rstream->input_peak_offset = 0;
rstream->eom = FALSE;
rstream->next_eof = FALSE;
}
int istream_raw_mbox_seek(struct istream *stream, uoff_t offset)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
int check;
rstream->corrupted = FALSE;
rstream->eom = FALSE;
rstream->next_eof = FALSE;
rstream->input_peak_offset = 0;
if (rstream->mail_size != (uoff_t)-1 &&
rstream->hdr_offset + rstream->mail_size == offset) {
istream_raw_mbox_next(stream, (uoff_t)-1);
return 0;
}
if (offset == rstream->from_offset) {
/* back to beginning of current message */
offset = rstream->hdr_offset;
check = offset == 0;
} else {
rstream->body_offset = (uoff_t)-1;
rstream->mail_size = (uoff_t)-1;
rstream->received_time = (time_t)-1;
rstream->next_received_time = (time_t)-1;
i_free(rstream->sender);
rstream->sender = NULL;
i_free(rstream->next_sender);
rstream->next_sender = NULL;
rstream->from_offset = offset;
rstream->hdr_offset = offset;
check = TRUE;
}
i_stream_seek(stream, offset);
i_stream_seek(rstream->input, offset);
if (check)
(void)_read(&rstream->istream);
return rstream->corrupted ? -1 : 0;
}
void istream_raw_mbox_flush(struct istream *stream)
{
struct raw_mbox_istream *rstream =
(struct raw_mbox_istream *)stream->real_stream;
/* kludgy */
rstream->input->real_stream->skip = 0;
rstream->input->real_stream->pos = 0;
rstream->istream.skip = 0;
rstream->istream.pos = 0;
}