dovecot-2.2: imap: Rewrote FETCH command to use imap-msgpart API.

dovecot at dovecot.org dovecot at dovecot.org
Thu Jun 21 21:54:03 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.2/rev/df8ba29d9eb3
changeset: 14623:df8ba29d9eb3
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Jun 21 21:52:56 2012 +0300
description:
imap: Rewrote FETCH command to use imap-msgpart API.

diffstat:

 src/imap/cmd-select.c      |    1 -
 src/imap/imap-client.h     |   12 -
 src/imap/imap-fetch-body.c |  811 ++++++++------------------------------------
 src/imap/imap-fetch.c      |    5 +-
 src/imap/imap-fetch.h      |    5 +-
 5 files changed, 156 insertions(+), 678 deletions(-)

diffs (truncated from 1095 to 300 lines):

diff -r 6fb61872b30a -r df8ba29d9eb3 src/imap/cmd-select.c
--- a/src/imap/cmd-select.c	Thu Jun 21 21:50:35 2012 +0300
+++ b/src/imap/cmd-select.c	Thu Jun 21 21:52:56 2012 +0300
@@ -301,7 +301,6 @@
 				STATUS_HIGHESTMODSEQ, &status);
 
 	client->mailbox = ctx->box;
-	client->select_counter++;
 	client->mailbox_examined = readonly;
 	client->messages_count = status.messages;
 	client->recent_count = status.recent;
diff -r 6fb61872b30a -r df8ba29d9eb3 src/imap/imap-client.h
--- a/src/imap/imap-client.h	Thu Jun 21 21:50:35 2012 +0300
+++ b/src/imap/imap-client.h	Thu Jun 21 21:52:56 2012 +0300
@@ -78,15 +78,6 @@
 	unsigned int temp_executed:1; /* temporary execution state tracking */
 };
 
-struct partial_fetch_cache {
-	unsigned int select_counter;
-	unsigned int uid;
-
-	uoff_t physical_start;
-	bool cr_skipped;
-	struct message_size pos;
-};
-
 struct imap_client_vfuncs {
 	void (*destroy)(struct client *client, const char *reason);
 };
@@ -111,7 +102,6 @@
         struct mail_user *user;
 	struct mailbox *mailbox;
         struct mailbox_keywords keywords;
-	unsigned int select_counter; /* increased when mailbox is changed */
 	unsigned int sync_counter;
 	uint32_t messages_count, recent_count, uidvalidity;
 	enum mailbox_feature enabled_features;
@@ -130,8 +120,6 @@
 	uint64_t sync_last_full_modseq;
 	uint64_t highest_fetch_modseq;
 
-	struct partial_fetch_cache last_partial;
-
 	/* SEARCHRES extension: Last saved SEARCH result */
 	ARRAY_TYPE(seq_range) search_saved_uidset;
 	/* SEARCH=CONTEXT extension: Searches that get updated */
diff -r 6fb61872b30a -r df8ba29d9eb3 src/imap/imap-fetch-body.c
--- a/src/imap/imap-fetch-body.c	Thu Jun 21 21:50:35 2012 +0300
+++ b/src/imap/imap-fetch-body.c	Thu Jun 21 21:52:56 2012 +0300
@@ -10,6 +10,7 @@
 #include "message-parser.h"
 #include "message-send.h"
 #include "mail-storage-private.h"
+#include "imap-quote.h"
 #include "imap-parser.h"
 #include "imap-msgpart.h"
 #include "imap-fetch.h"
@@ -19,17 +20,10 @@
 #include <unistd.h>
 
 struct imap_fetch_body_data {
-	struct imap_fetch_body_data *next;
+	const char *section; /* NOTE: always uppercased */
+	struct imap_msgpart *msgpart;
 
-        struct mailbox_header_lookup_ctx *header_ctx;
-	const char *section; /* NOTE: always uppercased */
-	uoff_t skip, max_size; /* if you don't want max_size,
-	                          set it to (uoff_t)-1 */
-
-	const char *const *fields;
-	size_t fields_count;
-
-	unsigned int skip_set:1;
+	unsigned int partial:1;
 	unsigned int peek:1;
 };
 
@@ -42,54 +36,16 @@
 		mailbox_get_vname(ctx->cur_mail->box), ctx->cur_mail->uid);
 }
 
-static int seek_partial(unsigned int select_counter, unsigned int uid,
-			struct partial_fetch_cache *partial,
-			struct istream *stream,
-			uoff_t virtual_skip, bool *cr_skipped_r)
-{
-	if (select_counter == partial->select_counter && uid == partial->uid &&
-	    stream->v_offset == partial->physical_start &&
-	    virtual_skip >= partial->pos.virtual_size) {
-		/* we can use the cache */
-		virtual_skip -= partial->pos.virtual_size;
-	} else {
-		partial->select_counter = select_counter;
-		partial->uid = uid;
-		partial->physical_start = stream->v_offset;
-		partial->cr_skipped = FALSE;
-		memset(&partial->pos, 0, sizeof(partial->pos));
-	}
-
-	i_stream_seek(stream, partial->physical_start +
-		      partial->pos.physical_size);
-	if (message_skip_virtual(stream, virtual_skip, &partial->pos,
-				 partial->cr_skipped, cr_skipped_r) < 0)
-		return -1;
-
-	partial->cr_skipped = FALSE;
-	return 0;
-}
-
-static uoff_t get_send_size(const struct imap_fetch_body_data *body,
-			    uoff_t max_size)
-{
-	uoff_t size;
-
-	if (body->skip >= max_size)
-		return 0;
-
-	size = max_size - body->skip;
-	return size <= body->max_size ? size : body->max_size;
-}
-
 static const char *get_body_name(const struct imap_fetch_body_data *body)
 {
 	string_t *str;
 
 	str = t_str_new(128);
 	str_printfa(str, "BODY[%s]", body->section);
-	if (body->skip_set)
-		str_printfa(str, "<%"PRIuUOFF_T">", body->skip);
+	if (body->partial) {
+		str_printfa(str, "<%"PRIuUOFF_T">",
+			    imap_msgpart_get_partial_offset(body->msgpart));
+	}
 	return str_c(str);
 }
 
@@ -114,131 +70,7 @@
 	return str;
 }
 
-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->cur_mail->box),
-			ctx->cur_mail->uid, (uoff_t)sent, virtual_size);
-		mail_set_cache_corrupted(ctx->cur_mail, ctx->cur_size_field);
-		client_disconnect(ctx->client, "FETCH failed");
-		return -1;
-	}
-
-	*last_cr = cr_skipped;
-	return sent;
-}
-
-static int fetch_stream_send(struct imap_fetch_context *ctx)
-{
-	off_t ret;
-
-	o_stream_set_max_buffer_size(ctx->client->output, 4096);
-	ret = imap_fetch_send(ctx, ctx->client->output, ctx->cur_input,
-			      ctx->skip_cr, ctx->cur_size - ctx->cur_offset,
-			      ctx->cur_append_eoh, &ctx->skip_cr);
-	o_stream_set_max_buffer_size(ctx->client->output, (size_t)-1);
-
-	if (ret < 0)
-		return -1;
-
-	ctx->cur_offset += ret;
-	if (ctx->update_partial) {
-		struct partial_fetch_cache *p = &ctx->client->last_partial;
-
-		p->cr_skipped = ctx->skip_cr != 0;
-		p->pos.physical_size =
-			ctx->cur_input->v_offset - p->physical_start;
-		p->pos.virtual_size += ret;
-	}
-
-	return ctx->cur_offset == ctx->cur_size;
-}
-
-static int fetch_stream_send_direct(struct imap_fetch_context *ctx)
+static int fetch_stream_continue(struct imap_fetch_context *ctx)
 {
 	off_t ret;
 
@@ -246,25 +78,20 @@
 	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 (ret > 0)
+		ctx->cur_offset += ret;
 
 	if (ctx->cur_offset != ctx->cur_size) {
 		/* unfinished */
+		if (ctx->cur_input->stream_errno != 0) {
+			fetch_read_error(ctx);
+			client_disconnect(ctx->client, "FETCH failed");
+			return -1;
+		}
 		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 "


More information about the dovecot-cvs mailing list