istream-raw-mbox.c revision 8ed8c821ba8aab0b4ed0375f87d48737ef0e0d8e
5a580c3a38ced62d4bcc95b8ac7c4f2935b5d294Timo Sirainen/* Copyright (c) 2003-2008 Dovecot authors, see the included COPYING file */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch uoff_t from_offset, hdr_offset, body_offset, mail_size;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Boschstatic void i_stream_raw_mbox_destroy(struct iostream_private *stream)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
7384b4e78eaab44693c985192276e31322155e32Stephan Boschi_stream_raw_mbox_set_max_buffer_size(struct iostream_private *stream,
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_stream_set_max_buffer_size(rstream->istream.parent, max_size);
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic int mbox_read_from_line(struct raw_mbox_istream *rstream)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch const unsigned char *buf, *p;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch buf = i_stream_get_data(rstream->istream.parent, &pos);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* from_offset points to "\nFrom ", so unless we're at the beginning
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen of the file, skip the initial \n */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch while ((p = memchr(buf+skip, '\n', pos-skip)) == NULL) {
1bc12a53ddc6696bb209fb79d7cc66262d2ea621Timo Sirainen if (i_stream_read(rstream->istream.parent) < 0) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* EOF shouldn't happen */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch buf = i_stream_get_data(rstream->istream.parent, &pos);
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* beginning of mbox */
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch mbox_from_parse(buf+5, pos-5, &received_time, &tz, &sender) < 0) {
6dad0888fcec8372f230941c70d8940b8c203b32Stephan Bosch /* broken From - should happen only at beginning of
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen file if this isn't a mbox.. */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch rstream->istream.istream.stream_errno = EINVAL;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (rstream->istream.istream.v_offset == rstream->from_offset) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* we'll skip over From-line */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch rstream->istream.istream.v_offset += line_pos+1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen i_stream_skip(rstream->istream.parent, line_pos+1);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch rstream->hdr_offset = rstream->istream.istream.v_offset;
7384b4e78eaab44693c985192276e31322155e32Stephan Boschstatic void handle_end_of_mail(struct raw_mbox_istream *rstream, size_t pos)
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch rstream->mail_size = rstream->istream.istream.v_offset + pos -
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (rstream->hdr_offset + rstream->mail_size < rstream->body_offset) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* Header didn't have ending \n */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* "headers\n\nFrom ..", the second \n belongs to next
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch message which we didn't know at the time yet. */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* The +2 check is for CR+LF linefeeds */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch i_assert(rstream->body_offset == (uoff_t)-1 ||
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch rstream->body_offset == new_body_offset + 1 ||
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Boschstatic ssize_t i_stream_raw_mbox_read(struct istream_private *stream)
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch struct raw_mbox_istream *rstream = (struct raw_mbox_istream *)stream;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch const unsigned char *buf;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch size_t i, pos, new_pos, from_start_pos, from_after_pos;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch i_assert(stream->istream.v_offset >= rstream->from_offset);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch rstream->istream.istream.stream_errno = EINVAL;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch i_stream_seek(stream->parent, stream->istream.v_offset);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch buf = i_stream_get_data(stream->parent, &pos);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch if (pos > 1 && stream->istream.v_offset + pos >
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* fake our read count. needed because if in the end
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch we have only one character in buffer and we skip it
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch (as potential CR), we want to get back to this
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch i_stream_raw_mbox_read() to read more data. */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch } while (ret > 0);
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch stream->istream.stream_errno = stream->parent->stream_errno;
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch } else if (stream->istream.v_offset != 0 || pos == 0) {
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* we've read the whole file, final byte should be
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch the \n trailer */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen if (stream->istream.v_offset == rstream->from_offset) {
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* haven't seen From-line yet, so this mbox
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen stream is now at EOF */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen return ret < 0 ? i_stream_raw_mbox_read(stream) : ret;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (stream->istream.v_offset == rstream->from_offset) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* beginning of message, we haven't yet read our From-line */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch /* we're at the end of file with CR+LF linefeeds?
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch need more data to verify it. */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* got it. we don't want to return it however,
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch so start again from headers */
a62fe4b300e2f591e939993aec4cac1e7ae30ad1Stephan Bosch buf = i_stream_get_data(stream->parent, &pos);
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* See if we have From-line here - note that it works right only
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch because all characters are different in mbox_from. */
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch fromp = mbox_from; from_start_pos = from_after_pos = (size_t)-1;
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen eoh_char = rstream->body_offset == (uoff_t)-1 ? '\n' : -1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch (i > 1 && buf[i-1] == '\r' && buf[i-2] == '\n') ||
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch stream->istream.v_offset + i == rstream->hdr_offset)) {
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch rstream->body_offset = stream->istream.v_offset + i + 1;
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* potential From-line, see if we have the
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch rest of the line buffered.
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch FIXME: if From-line is longer than input
208dcaf62332b80b220c8c66e776f7cc0c39253bStephan Bosch buffer, we break. probably irrelevant.. */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch if (rstream->hdr_offset + rstream->mail_size ==
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* CR also belongs to it. */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* we have the whole From-line here now.
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch See if it's a valid one. */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch /* yep, we stop here. */
b72c3363092b73cab1da2de4a9d75592e7d8fd6bTimo Sirainen /* we want to go at least one byte further next time */
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch rstream->input_peak_offset = stream->istream.v_offset + i;
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch /* we're waiting for the \n at the end of From-line */
6a90041707f1290c8970a3bacb0f8f928aeaaba6Stephan Bosch /* leave out the beginnings of potential From-line + CR */
7384b4e78eaab44693c985192276e31322155e32Stephan Bosch rstream->hdr_offset + new_pos > rstream->mail_size) {
return ret;
static const struct stat *
return NULL;
struct istream *
const unsigned char *data;
char *sender;
int tz;
const unsigned char *data;
return body_size;
return expected_body_size;
return body_size;
bool check;
if (check)