istream-mbox.c revision 8cba3d69f0d0a3f03dc3b630e18896aa00ebb6ff
45312f52ff3a3d4c137447be4c7556500c2f8bf2Timo Sirainen/* Copyright (C) 2003 Timo Sirainen */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "lib.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "buffer.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "message-parser.h"
0cb2e8eb55e70f8ebe1e8349bdf49e4cbe5d8834Timo Sirainen#include "istream-internal.h"
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen#include "mbox-index.h"
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct mbox_istream {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct _istream istream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct istream *input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_t *headers;
137ea7ca34005345aa2304a940149b7f3774d727Timo Sirainen uoff_t body_offset, body_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct message_size header_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen};
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void _close(struct _iostream *stream __attr_unused__)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void _destroy(struct _iostream *stream)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mbox_istream *mstream = (struct mbox_istream *) stream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_unref(mstream->input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen buffer_free(mstream->headers);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mbox_istream *mstream = (struct mbox_istream *) stream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_set_max_buffer_size(mstream->input, max_size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void _set_blocking(struct _iostream *stream, int timeout_msecs,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen void (*timeout_cb)(void *), void *context)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mbox_istream *mstream = (struct mbox_istream *) stream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_set_blocking(mstream->input, timeout_msecs,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen timeout_cb, context);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic ssize_t _read(struct _istream *stream)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mbox_istream *mstream = (struct mbox_istream *) stream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ssize_t ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen size_t pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t limit, old_limit;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen off_t vsize_diff;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (stream->istream.v_offset < mstream->header_size.virtual_size) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* we don't support mixing headers and body.
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen it shouldn't be needed. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return -2;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* may be positive or negative, depending on how much there was CRs
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen and how much headers were hidden */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen vsize_diff = mstream->header_size.virtual_size -
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->header_size.physical_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen limit = stream->istream.v_limit - vsize_diff;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen old_limit = mstream->input->v_limit;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (limit != old_limit)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_set_read_limit(mstream->input, limit);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (mstream->input->v_offset != stream->istream.v_offset - vsize_diff) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_seek(mstream->input,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->istream.v_offset - vsize_diff);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = i_stream_read(mstream->input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.skip = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.buffer = i_stream_get_data(mstream->input, &pos);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (pos == mstream->istream.pos)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = -1;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen ret = mstream->istream.pos - pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.pos = pos;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (limit != old_limit)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_set_read_limit(mstream->input, old_limit);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return ret;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void _seek(struct _istream *stream, uoff_t v_offset)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mbox_istream *mstream = (struct mbox_istream *) stream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->istream.v_offset = v_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (v_offset < mstream->header_size.virtual_size) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* still in headers */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->skip = v_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->pos = stream->high_pos =
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->header_size.virtual_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->buffer = buffer_get_data(mstream->headers, NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen } else {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* body - use our real input stream */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->skip = stream->pos = stream->high_pos = 0;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen stream->buffer = NULL;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen v_offset += mstream->header_size.physical_size -
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->header_size.virtual_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_seek(mstream->input, v_offset);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstatic void _skip(struct _istream *stream, uoff_t count)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_seek(&stream->istream, stream->istream.v_offset + count);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainenstruct istream *i_stream_create_mbox(pool_t pool, struct istream *input,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen uoff_t body_size)
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen{
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen struct mbox_istream *mstream;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream = p_new(pool, struct mbox_istream, 1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->input = input;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->body_size = body_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen if (body_size == 0) {
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen /* possibly broken message, find the next From-line
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen and make sure header parser won't pass it. */
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mbox_skip_header(input);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_set_read_limit(input, input->v_offset);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_seek(input, 0);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen }
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->headers = buffer_create_dynamic(default_pool,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen 8192, (size_t)-1);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mbox_hide_headers(input, mstream->headers,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen &mstream->header_size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->body_offset = input->v_offset;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen i_stream_set_read_limit(input, mstream->body_offset + body_size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.buffer = buffer_get_data(mstream->headers, NULL);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.pos = mstream->header_size.virtual_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.iostream.close = _close;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.iostream.destroy = _destroy;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.iostream.set_blocking = _set_blocking;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.read = _read;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.skip_count = _skip;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->istream.seek = _seek;
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen return _i_stream_create(&mstream->istream, pool, -1, 0,
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen mstream->header_size.virtual_size + body_size);
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen}
0c17af9d3f9323136a94e66605776ed4462a172dTimo Sirainen