コード例 #1
0
ファイル: index-mail.c プロジェクト: via/dovecot-clouddb
void index_mail_close(struct mail *_mail)
{
	struct index_mail *mail = (struct index_mail *)_mail;
	struct message_part *parts;

	/* If uid == 0 but seq != 0, we came here from saving a (non-mbox)
	   message. If that happens, don't bother checking if anything should
	   be cached since it was already checked. Also by now the transaction
	   may have already been rollbacked and seq point to a nonexistent
	   message. */
	if (mail->mail.mail.uid != 0) {
		index_mail_cache_sizes(mail);
		index_mail_cache_dates(mail);
	}

	if (mail->data.parser_ctx != NULL) {
		if (message_parser_deinit(&mail->data.parser_ctx, &parts) < 0) {
			mail_set_cache_corrupted(_mail,
						 MAIL_FETCH_MESSAGE_PARTS);
		}
	}
	if (mail->data.filter_stream != NULL)
		i_stream_unref(&mail->data.filter_stream);
	if (mail->data.stream != NULL) {
		mail->data.destroying_stream = TRUE;
		i_stream_unref(&mail->data.stream);
		i_assert(!mail->data.destroying_stream);
	}
}
コード例 #2
0
ファイル: index-mail.c プロジェクト: via/dovecot-clouddb
static int index_mail_parse_body_finish(struct index_mail *mail,
					enum index_cache_field field)
{
	if (message_parser_deinit(&mail->data.parser_ctx,
				  &mail->data.parts) < 0) {
		mail_set_cache_corrupted(&mail->mail.mail,
					 MAIL_FETCH_MESSAGE_PARTS);
		mail->data.parsed_bodystructure = FALSE;
		return -1;
	}
	if (mail->data.no_caching) {
		/* if we're here because we aborted parsing, don't get any
		   further or we may crash while generating output from
		   incomplete data */
		return 0;
	}

	(void)get_cached_msgpart_sizes(mail);

	index_mail_body_parsed_cache_flags(mail);
	index_mail_body_parsed_cache_message_parts(mail);
	index_mail_body_parsed_cache_bodystructure(mail, field);
	index_mail_cache_sizes(mail);
	index_mail_cache_dates(mail);
	return 0;
}
コード例 #3
0
ファイル: virtual-mail.c プロジェクト: via/dovecot-clouddb
static void
virtual_mail_set_cache_corrupted(struct mail *mail, enum mail_fetch_field field)
{
	struct virtual_mail *vmail = (struct virtual_mail *)mail;

	if (virtual_mail_handle_lost(vmail) < 0)
		return;
	mail_set_cache_corrupted(vmail->backend_mail, field);
}
コード例 #4
0
ファイル: imap-fetch-body.c プロジェクト: bsmr-dovecot/core
static int fetch_stream_continue(struct imap_fetch_context *ctx)
{
	struct imap_fetch_state *state = &ctx->state;
	const char *disconnect_reason;
	off_t ret;

	o_stream_set_max_buffer_size(ctx->client->output, 0);
	ret = o_stream_send_istream(ctx->client->output, state->cur_input);
	o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);

	if (ret > 0) {
		state->cur_offset += ret;
		if (ctx->state.cur_stats_sizep != NULL)
			*ctx->state.cur_stats_sizep += ret;
	}

	if (state->cur_offset != state->cur_size) {
		/* unfinished */
		if (state->cur_input->stream_errno != 0) {
			fetch_read_error(ctx, &disconnect_reason);
			client_disconnect(ctx->client, disconnect_reason);
			return -1;
		}
		if (!i_stream_have_bytes_left(state->cur_input)) {
			/* Input stream gave less data than expected */
			i_error("read(%s): FETCH %s for mailbox %s UID %u "
				"got too little data: "
				"%"PRIuUOFF_T" vs %"PRIuUOFF_T,
				i_stream_get_name(state->cur_input),
				state->cur_human_name,
				mailbox_get_vname(state->cur_mail->box),
				state->cur_mail->uid,
				state->cur_offset, state->cur_size);
			mail_set_cache_corrupted(state->cur_mail,
						 state->cur_size_field);
			client_disconnect(ctx->client, "FETCH failed");
			return -1;
		}
		if (ret < 0) {
			/* client probably disconnected */
			return -1;
		}

		o_stream_set_flush_pending(ctx->client->output, TRUE);
		return 0;
	}
	return 1;
}
コード例 #5
0
ファイル: imap-fetch-body.c プロジェクト: manuelm/dovecot
static int fetch_stream_continue(struct imap_fetch_context *ctx)
{
	struct imap_fetch_state *state = &ctx->state;
	const char *disconnect_reason;
	uoff_t orig_input_offset = state->cur_input->v_offset;
	enum ostream_send_istream_result res;

	o_stream_set_max_buffer_size(ctx->client->output, 0);
	res = o_stream_send_istream(ctx->client->output, state->cur_input);
	o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);

	if (ctx->state.cur_stats_sizep != NULL) {
		*ctx->state.cur_stats_sizep +=
			state->cur_input->v_offset - orig_input_offset;
	}

	switch (res) {
	case OSTREAM_SEND_ISTREAM_RESULT_FINISHED:
		if (state->cur_input->v_offset != state->cur_size) {
			/* Input stream gave less data than expected */
			mail_set_cache_corrupted(state->cur_mail,
				state->cur_size_field, t_strdup_printf(
				"read(%s): FETCH %s got too little data: "
				"%"PRIuUOFF_T" vs %"PRIuUOFF_T,
				i_stream_get_name(state->cur_input),
				state->cur_human_name,
				state->cur_input->v_offset, state->cur_size));
			client_disconnect(ctx->client, "FETCH failed");
			return -1;
		}
		return 1;
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT:
		i_unreached();
	case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT:
		return 0;
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT:
		fetch_read_error(ctx, &disconnect_reason);
		client_disconnect(ctx->client, disconnect_reason);
		return -1;
	case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT:
		/* client disconnected */
		return -1;
	}
	i_unreached();
}
コード例 #6
0
ファイル: imap-fetch-body.c プロジェクト: via/dovecot-clouddb
static int fetch_stream_send_direct(struct imap_fetch_context *ctx)
{
	off_t ret;

	o_stream_set_max_buffer_size(ctx->client->output, 0);
	ret = o_stream_send_istream(ctx->client->output, ctx->cur_input);
	o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);

	if (ret < 0)
		return -1;

	ctx->cur_offset += ret;

	if (ctx->cur_append_eoh && ctx->cur_offset + 2 == ctx->cur_size) {
		/* Netscape missing EOH workaround. */
		if (o_stream_send(ctx->client->output, "\r\n", 2) < 0)
			return -1;
		ctx->cur_offset += 2;
		ctx->cur_append_eoh = FALSE;
	}

	if (ctx->cur_offset != ctx->cur_size) {
		/* unfinished */
		if (!i_stream_have_bytes_left(ctx->cur_input)) {
			/* Input stream gave less data than expected */
			i_error("FETCH %s for mailbox %s UID %u "
				"got too little data (copying): "
				"%"PRIuUOFF_T" vs %"PRIuUOFF_T,
				ctx->cur_name, mailbox_get_vname(ctx->mail->box),
				ctx->mail->uid, ctx->cur_offset, ctx->cur_size);
			mail_set_cache_corrupted(ctx->mail,
						 ctx->cur_size_field);
			client_disconnect(ctx->client, "FETCH failed");
			return -1;
		}

		o_stream_set_flush_pending(ctx->client->output, TRUE);
		return 0;
	}
	return 1;
}
コード例 #7
0
ファイル: istream-mail.c プロジェクト: Distrotech/dovecot
static void
i_stream_mail_set_size_corrupted(struct mail_istream *mstream, size_t size)
{
	uoff_t cur_size = mstream->istream.istream.v_offset + size;
	const char *str;
	char chr;

	if (mstream->expected_size < cur_size) {
		str = "smaller";
		chr = '<';
	} else {
		str = "larger";
		chr = '>';
	}

	mail_storage_set_critical(mstream->mail->box->storage,
		"Cached message size %s than expected "
		"(%"PRIuUOFF_T" %c %"PRIuUOFF_T")", str,
		mstream->expected_size, chr, cur_size);
	mail_set_cache_corrupted(mstream->mail, MAIL_FETCH_PHYSICAL_SIZE);
	mstream->istream.istream.stream_errno = EINVAL;
}
コード例 #8
0
ファイル: index-mail.c プロジェクト: via/dovecot-clouddb
int index_mail_get_special(struct mail *_mail,
			   enum mail_fetch_field field, const char **value_r)
{
	struct index_mail *mail = (struct index_mail *)_mail;
	struct index_mail_data *data = &mail->data;
	struct mail_cache_field *cache_fields = mail->ibox->cache_fields;
	string_t *str;

	switch (field) {
	case MAIL_FETCH_IMAP_BODY: {
		unsigned int body_cache_field =
                        cache_fields[MAIL_CACHE_IMAP_BODY].idx;
		unsigned int bodystructure_cache_field =
                        cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;

		if (data->body != NULL) {
			*value_r = data->body;
			return 0;
		}

		/* 1) use plain-7bit-ascii flag if it exists
		   2) get BODY if it exists
		   3) get it using BODYSTRUCTURE if it exists
		   4) parse body structure, and save BODY/BODYSTRUCTURE
		      depending on what we want cached */

		str = str_new(mail->data_pool, 128);
		if ((mail->data.cache_flags &
		     MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 &&
		    get_cached_parts(mail)) {
			index_mail_get_plain_bodystructure(mail, str, FALSE);
			data->body = str_c(str);
		} else if (index_mail_cache_lookup_field(mail, str,
							 body_cache_field) > 0)
			data->body = str_c(str);
		else if (index_mail_cache_lookup_field(mail, str,
					bodystructure_cache_field) > 0) {
			data->bodystructure =
				p_strdup(mail->data_pool, str_c(str));
			str_truncate(str, 0);

			if (imap_body_parse_from_bodystructure(
						data->bodystructure, str))
				data->body = str_c(str);
			else {
				/* broken, continue.. */
				mail_set_cache_corrupted(_mail,
					MAIL_FETCH_IMAP_BODYSTRUCTURE);
			}
		}

		if (data->body == NULL) {
			str_free(&str);
			if (index_mail_parse_bodystructure(mail,
						MAIL_CACHE_IMAP_BODY) < 0)
				return -1;
		}
		i_assert(data->body != NULL);
		*value_r = data->body;
		return 0;
	}
	case MAIL_FETCH_IMAP_BODYSTRUCTURE: {
		unsigned int bodystructure_cache_field =
                        cache_fields[MAIL_CACHE_IMAP_BODYSTRUCTURE].idx;

		if (data->bodystructure != NULL) {
			*value_r = data->bodystructure;
			return 0;
		}

		str = str_new(mail->data_pool, 128);
		if ((mail->data.cache_flags &
		     MAIL_CACHE_FLAG_TEXT_PLAIN_7BIT_ASCII) != 0 &&
		    get_cached_parts(mail)) {
			index_mail_get_plain_bodystructure(mail, str, TRUE);
			data->bodystructure = str_c(str);
		} else if (index_mail_cache_lookup_field(mail, str,
					bodystructure_cache_field) > 0) {
			data->bodystructure = str_c(str);
		} else {
			str_free(&str);
			if (index_mail_parse_bodystructure(mail,
					MAIL_CACHE_IMAP_BODYSTRUCTURE) < 0)
				return -1;
		}
		i_assert(data->bodystructure != NULL);
		*value_r = data->bodystructure;
		return 0;
	}
	case MAIL_FETCH_IMAP_ENVELOPE:
		if (data->envelope == NULL) {
			if (index_mail_headers_get_envelope(mail) < 0)
				return -1;
		}
		*value_r = data->envelope;
		return 0;
	case MAIL_FETCH_FROM_ENVELOPE:
	case MAIL_FETCH_UIDL_FILE_NAME:
	case MAIL_FETCH_UIDL_BACKEND:
	case MAIL_FETCH_SEARCH_SCORE:
	case MAIL_FETCH_GUID:
	case MAIL_FETCH_HEADER_MD5:
		*value_r = "";
		return 0;
	case MAIL_FETCH_MAILBOX_NAME:
		*value_r = _mail->box->vname;
		return 0;
	default:
		i_unreached();
		return -1;
	}
}
コード例 #9
0
ファイル: imap-fetch-body.c プロジェクト: via/dovecot-clouddb
static off_t imap_fetch_send(struct imap_fetch_context *ctx,
			     struct ostream *output, struct istream *input,
			     bool cr_skipped, uoff_t virtual_size,
			     bool add_missing_eoh, bool *last_cr)
{
	const unsigned char *msg;
	size_t i, size;
	uoff_t vsize_left, sent;
	off_t ret;
	unsigned char add;
	bool blocks = FALSE;

	/* go through the message data and insert CRs where needed.  */
	sent = 0; vsize_left = virtual_size;
	while (vsize_left > 0 && !blocks &&
	       i_stream_read_data(input, &msg, &size, 0) > 0) {
		add = '\0';
		for (i = 0; i < size && vsize_left > 0; i++) {
			vsize_left--;

			if (msg[i] == '\n') {
				if ((i > 0 && msg[i-1] != '\r') ||
				    (i == 0 && !cr_skipped)) {
					/* missing CR */
					add = '\r';
					break;
				}
			} else if (msg[i] == '\0') {
				add = 128;
				break;
			}
		}

		if ((ret = o_stream_send(output, msg, i)) < 0)
			return -1;
		if ((uoff_t)ret < i) {
			add = '\0';
			blocks = TRUE;
		}

		if (ret > 0)
			cr_skipped = msg[ret-1] == '\r';

		i_stream_skip(input, ret);
		sent += ret;

		if (add != '\0') {
			if ((ret = o_stream_send(output, &add, 1)) < 0)
				return -1;
			if (ret == 0)
				blocks = TRUE;
			else {
				sent++;
				cr_skipped = add == '\r';
				if (add == 128)
					i_stream_skip(input, 1);
			}
		}
	}
	if (input->stream_errno != 0) {
		fetch_read_error(ctx);
		return -1;
	}

	if (add_missing_eoh && sent + 2 == virtual_size) {
		/* Netscape missing EOH workaround. */
		o_stream_set_max_buffer_size(output, (size_t)-1);
		if (o_stream_send(output, "\r\n", 2) < 0)
			return -1;
		sent += 2;
	}

	if ((uoff_t)sent != virtual_size && !blocks) {
		/* Input stream gave less data than we expected. Two choices
		   here: either we fill the missing data with spaces or we
		   disconnect the client.

		   We shouldn't really ever get here. One reason is if mail
		   was deleted from NFS server while we were reading it.
		   Another is some temporary disk error.

		   If we filled the missing data the client could cache it,
		   and if it was just a temporary error the message would be
		   permanently left corrupted in client's local cache. So, we
		   disconnect the client and hope that next try works. */
		i_error("FETCH %s for mailbox %s UID %u got too little data: "
			"%"PRIuUOFF_T" vs %"PRIuUOFF_T, ctx->cur_name,
			mailbox_get_vname(ctx->mail->box), ctx->mail->uid,
			(uoff_t)sent, virtual_size);
		mail_set_cache_corrupted(ctx->mail, ctx->cur_size_field);
		client_disconnect(ctx->client, "FETCH failed");
		return -1;
	}

	*last_cr = cr_skipped;
	return sent;
}