view src/lib-index/mbox/istream-mbox.c @ 1855:56cec02d8f8c HEAD

fix
author Timo Sirainen <tss@iki.fi>
date Wed, 29 Oct 2003 17:01:36 +0200
parents d4a2788f5fa6
children 34bdf8beb23a
line wrap: on
line source

/* Copyright (C) 2003 Timo Sirainen */

#include "lib.h"
#include "buffer.h"
#include "message-parser.h"
#include "istream-internal.h"
#include "mbox-index.h"

struct mbox_istream {
	struct _istream istream;

	struct istream *input;

	buffer_t *headers;
	uoff_t body_offset, body_size;
	struct message_size header_size;
};

static void _close(struct _iostream *stream __attr_unused__)
{
}

static void _destroy(struct _iostream *stream)
{
	struct mbox_istream *mstream = (struct mbox_istream *) stream;

	i_stream_unref(mstream->input);
	buffer_free(mstream->headers);
}

static void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
{
	struct mbox_istream *mstream = (struct mbox_istream *) stream;

	i_stream_set_max_buffer_size(mstream->input, max_size);
}

static void _set_blocking(struct _iostream *stream, int timeout_msecs,
			  void (*timeout_cb)(void *), void *context)
{
	struct mbox_istream *mstream = (struct mbox_istream *) stream;

	i_stream_set_blocking(mstream->input, timeout_msecs,
			      timeout_cb, context);
}

static ssize_t _read(struct _istream *stream)
{
	struct mbox_istream *mstream = (struct mbox_istream *) stream;
	ssize_t ret;
	size_t pos;
	uoff_t limit, old_limit;
	off_t vsize_diff;

	if (stream->istream.v_offset < mstream->header_size.virtual_size) {
		/* we don't support mixing headers and body.
		   it shouldn't be needed. */
		return -2;
	}

	/* may be positive or negative, depending on how much there was CRs
	   and how much headers were hidden */
	vsize_diff = mstream->header_size.virtual_size -
		mstream->header_size.physical_size;

	limit = stream->istream.v_limit - vsize_diff;
	old_limit = mstream->input->v_limit;
	if (limit != old_limit)
		i_stream_set_read_limit(mstream->input, limit);

	if (mstream->input->v_offset != stream->istream.v_offset - vsize_diff) {
		i_stream_seek(mstream->input,
			      stream->istream.v_offset - vsize_diff);
	}

	ret = i_stream_read(mstream->input);

	mstream->istream.skip = 0;
	mstream->istream.buffer = i_stream_get_data(mstream->input, &pos);

	if (pos <= mstream->istream.pos)
		ret = -1;
	else {
		ret = pos - mstream->istream.pos;
                mstream->istream.pos = pos;
	}

	if (limit != old_limit)
		i_stream_set_read_limit(mstream->input, old_limit);
	return ret;
}

static void _seek(struct _istream *stream, uoff_t v_offset)
{
	struct mbox_istream *mstream = (struct mbox_istream *) stream;

	stream->istream.v_offset = v_offset;
	if (v_offset < mstream->header_size.virtual_size) {
		/* still in headers */
		stream->skip = v_offset;
		stream->pos = stream->high_pos =
			mstream->header_size.virtual_size;
		stream->buffer = buffer_get_data(mstream->headers, NULL);
	} else {
		/* body - use our real input stream */
		stream->skip = stream->pos = stream->high_pos = 0;
		stream->buffer = NULL;

		v_offset += mstream->header_size.physical_size -
			mstream->header_size.virtual_size;
		i_stream_seek(mstream->input, v_offset);
	}
}

static void _skip(struct _istream *stream, uoff_t count)
{
	i_stream_seek(&stream->istream, stream->istream.v_offset + count);
}

struct istream *i_stream_create_mbox(pool_t pool, struct istream *input,
				     uoff_t body_size)
{
	struct mbox_istream *mstream;

	mstream = p_new(pool, struct mbox_istream, 1);
	mstream->input = input;
	mstream->body_size = body_size;

	if (body_size == 0) {
		/* possibly broken message, find the next From-line
		   and make sure header parser won't pass it. */
		mbox_skip_header(input);
		i_stream_set_read_limit(input, input->v_offset);
		i_stream_seek(input, 0);
	}

	mstream->headers = buffer_create_dynamic(default_pool,
						 8192, (size_t)-1);
	mbox_hide_headers(input, mstream->headers,
			  &mstream->header_size);
	mstream->body_offset = input->v_offset;
	i_stream_set_read_limit(input, mstream->body_offset + body_size);

	mstream->istream.buffer = buffer_get_data(mstream->headers, NULL);
	mstream->istream.pos = mstream->header_size.virtual_size;

	mstream->istream.iostream.close = _close;
	mstream->istream.iostream.destroy = _destroy;
	mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
	mstream->istream.iostream.set_blocking = _set_blocking;

	mstream->istream.read = _read;
	mstream->istream.skip_count = _skip;
	mstream->istream.seek = _seek;

	return _i_stream_create(&mstream->istream, pool, -1, 0,
				mstream->header_size.virtual_size + body_size);
}