changeset 6265:0ee2b0691f3e HEAD

Cache received date, sent date, save date and physical size when saving mails if they're wanted.
author Timo Sirainen <tss@iki.fi>
date Sat, 11 Aug 2007 14:35:36 +0300
parents 10acca6dd37d
children 3fabc189d17c
files src/lib-storage/index/cydir/cydir-save.c src/lib-storage/index/index-mail-headers.c src/lib-storage/index/index-mail.c src/lib-storage/index/index-mail.h src/lib-storage/index/maildir/maildir-save.c src/lib-storage/index/mbox/mbox-save.c
diffstat 6 files changed, 160 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib-storage/index/cydir/cydir-save.c	Sat Aug 11 14:27:40 2007 +0300
+++ b/src/lib-storage/index/cydir/cydir-save.c	Sat Aug 11 14:35:36 2007 +0300
@@ -29,6 +29,7 @@
 	struct istream *input;
 	struct ostream *output;
 	struct mail *mail, *cur_dest_mail;
+	time_t cur_received_date;
 	int fd;
 
 	unsigned int failed:1;
@@ -89,18 +90,6 @@
 		ctx->output = o_stream_create_crlf(output);
 		o_stream_unref(&output);
 		o_stream_cork(ctx->output);
-
-		if (received_date != (time_t)-1) {
-			struct utimbuf ut;
-
-			ut.actime = ioloop_time;
-			ut.modtime = received_date;
-			if (utime(path, &ut) < 0) {
-				mail_storage_set_critical(_t->box->storage,
-					"utime(%s) failed: %m", path);
-				/* ignore this error anyway */
-			}
-		}
 	} else {
 		mail_storage_set_critical(_t->box->storage,
 					  "open(%s) failed: %m", path);
@@ -130,6 +119,7 @@
 
 	ctx->cur_dest_mail = dest_mail;
 	ctx->input = index_mail_cache_parse_init(dest_mail, input);
+	ctx->cur_received_date = received_date;
 
 	*ctx_r = &ctx->ctx;
 	return ctx->failed ? -1 : 0;
@@ -167,6 +157,7 @@
 	struct cydir_save_context *ctx = (struct cydir_save_context *)_ctx;
 	struct mail_storage *storage = &ctx->mbox->storage->storage;
 	const char *path = cydir_get_save_path(ctx, ctx->mail_count);
+	struct stat st;
 
 	ctx->finished = TRUE;
 
@@ -184,6 +175,26 @@
 		}
 	}
 
+	if (ctx->cur_received_date == (time_t)-1) {
+		if (fstat(ctx->fd, &st) == 0)
+			ctx->cur_received_date = st.st_mtime;
+		else {
+			mail_storage_set_critical(storage,
+						  "fstat(%s) failed: %m", path);
+			ctx->failed = TRUE;
+		}
+	} else {
+		struct utimbuf ut;
+
+		ut.actime = ioloop_time;
+		ut.modtime = ctx->cur_received_date;
+		if (utime(path, &ut) < 0) {
+			mail_storage_set_critical(storage,
+						  "utime(%s) failed: %m", path);
+			ctx->failed = TRUE;
+		}
+	}
+
 	o_stream_destroy(&ctx->output);
 	if (close(ctx->fd) < 0) {
 		mail_storage_set_critical(storage,
@@ -201,7 +212,8 @@
 		}
 	}
 
-	index_mail_cache_parse_deinit(ctx->cur_dest_mail);
+	index_mail_cache_parse_deinit(ctx->cur_dest_mail,
+				      ctx->cur_received_date);
 	i_stream_unref(&ctx->input);
 
 	return ctx->failed ? -1 : 0;
--- a/src/lib-storage/index/index-mail-headers.c	Sat Aug 11 14:27:40 2007 +0300
+++ b/src/lib-storage/index/index-mail-headers.c	Sat Aug 11 14:35:36 2007 +0300
@@ -341,8 +341,8 @@
 	index_mail_parse_header(mail->data.parts, hdr, mail);
 }
 
-struct istream *index_mail_cache_parse_init(struct mail *_mail,
-					    struct istream *input)
+struct istream *
+index_mail_cache_parse_init(struct mail *_mail, struct istream *input)
 {
 	struct index_mail *mail = (struct index_mail *)_mail;
 	struct tee_istream *tee;
--- a/src/lib-storage/index/index-mail.c	Sat Aug 11 14:27:40 2007 +0300
+++ b/src/lib-storage/index/index-mail.c	Sat Aug 11 14:35:36 2007 +0300
@@ -3,6 +3,7 @@
 #include "lib.h"
 #include "array.h"
 #include "buffer.h"
+#include "ioloop.h"
 #include "istream.h"
 #include "hex-binary.h"
 #include "str.h"
@@ -225,11 +226,33 @@
 	return data->save_date;
 }
 
+static void index_mail_cache_sent_date(struct index_mail *mail)
+{
+	struct index_mail_data *data = &mail->data;
+	const char *str;
+	time_t t;
+	int tz;
+
+	if (data->sent_date.time != (uint32_t)-1)
+		return;
+
+	str = mail_get_first_header(&mail->mail.mail, "Date");
+	if (str == NULL || !message_date_parse((const unsigned char *)str,
+					       strlen(str), &t, &tz)) {
+		/* 0 = not found / invalid */
+		t = 0;
+		tz = 0;
+	}
+	data->sent_date.time = t;
+	data->sent_date.timezone = tz;
+	index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE,
+			     &data->sent_date, sizeof(data->sent_date));
+}
+
 time_t index_mail_get_date(struct mail *_mail, int *timezone)
 {
 	struct index_mail *mail = (struct index_mail *) _mail;
 	struct index_mail_data *data = &mail->data;
-	const char *str;
 
 	if (data->sent_date.time != (uint32_t)-1) {
 		if (timezone != NULL)
@@ -241,24 +264,7 @@
 					 &data->sent_date,
 					 sizeof(data->sent_date));
 
-	if (data->sent_date.time == (uint32_t)-1) {
-		time_t t;
-		int tz;
-
-		str = mail_get_first_header(_mail, "Date");
-		if (str == NULL ||
-		    !message_date_parse((const unsigned char *)str,
-					strlen(str), &t, &tz)) {
-			/* 0 = not found / invalid */
-			t = 0;
-			tz = 0;
-		}
-		data->sent_date.time = t;
-		data->sent_date.timezone = tz;
-		index_mail_cache_add(mail, MAIL_CACHE_SENT_DATE,
-				     &data->sent_date, sizeof(data->sent_date));
-	}
-
+	index_mail_cache_sent_date(mail);
 	if (timezone != NULL)
 		*timezone = data->sent_date.timezone;
 	return data->sent_date.time;
@@ -561,17 +567,27 @@
 	}
 }
 
-static void
-index_mail_body_parsed_cache_virtual_size(struct index_mail *mail)
+static void index_mail_body_parsed_cache_sizes(struct index_mail *mail)
 {
-	unsigned int cache_field =
-		mail->ibox->cache_fields[MAIL_CACHE_VIRTUAL_FULL_SIZE].idx;
+	static enum index_cache_field date_fields[] = {
+		MAIL_CACHE_VIRTUAL_FULL_SIZE,
+		MAIL_CACHE_PHYSICAL_FULL_SIZE
+	};
+	uoff_t sizes[N_ELEMENTS(date_fields)];
+	unsigned int i, cache_field;
 
-	if (mail_cache_field_want_add(mail->trans->cache_trans,
-				      mail->data.seq, cache_field)) {
-		index_mail_cache_add(mail, MAIL_CACHE_VIRTUAL_FULL_SIZE,
-				     &mail->data.virtual_size,
-				     sizeof(mail->data.virtual_size));
+	sizes[0] = mail->data.virtual_size;
+	sizes[1] = mail->data.physical_size;
+
+	for (i = 0; i < N_ELEMENTS(date_fields); i++) {
+		cache_field = mail->ibox->cache_fields[date_fields[i]].idx;
+
+		i_assert(sizes[i] != (uoff_t)-1);
+		if (mail_cache_field_want_add(mail->trans->cache_trans,
+					      mail->data.seq, cache_field)) {
+			index_mail_cache_add(mail, date_fields[i],
+					     &sizes[i], sizeof(sizes[i]));
+		}
 	}
 }
 
@@ -592,7 +608,7 @@
 	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_body_parsed_cache_virtual_size(mail);
+	index_mail_body_parsed_cache_sizes(mail);
 }
 
 static void index_mail_parse_body(struct index_mail *mail,
@@ -1095,13 +1111,54 @@
 	}
 }
 
-void index_mail_cache_parse_deinit(struct mail *_mail)
+static void index_mail_cache_dates(struct index_mail *mail)
+{
+	static enum index_cache_field date_fields[] = {
+		MAIL_CACHE_RECEIVED_DATE,
+		MAIL_CACHE_SAVE_DATE
+	};
+	time_t dates[N_ELEMENTS(date_fields)];
+	unsigned int i, cache_field;
+	uint32_t t;
+
+	dates[0] = mail->data.received_date;
+	dates[1] = mail->data.save_date;
+
+	for (i = 0; i < N_ELEMENTS(date_fields); i++) {
+		cache_field = mail->ibox->cache_fields[date_fields[i]].idx;
+
+		i_assert(dates[i] != (time_t)-1);
+		if (mail_cache_field_want_add(mail->trans->cache_trans,
+					      mail->data.seq, cache_field)) {
+			t = dates[i];
+			index_mail_cache_add(mail, date_fields[i],
+					     &t, sizeof(t));
+		}
+	}
+
+	cache_field = mail->ibox->cache_fields[MAIL_CACHE_SENT_DATE].idx;
+	if (mail_cache_field_want_add(mail->trans->cache_trans,
+				      mail->data.seq, cache_field))
+		index_mail_cache_sent_date(mail);
+}
+
+void index_mail_cache_parse_deinit(struct mail *_mail, time_t received_date)
 {
 	struct index_mail *mail = (struct index_mail *)_mail;
 
+	if (mail->data.received_date == (time_t)-1)
+		mail->data.received_date = received_date;
+	if (mail->data.save_date == (time_t)-1) {
+		/* this save_date may not be exactly the same as what we get
+		   in future, but then again neither mbox nor maildir
+		   guarantees it anyway. */
+		mail->data.save_date = ioloop_time;
+	}
+
 	mail->data.save_bodystructure_body = FALSE;
 	mail->data.parsed_bodystructure = TRUE;
 	index_mail_parse_body_finish(mail, 0, TRUE);
+	index_mail_cache_dates(mail);
 }
 
 int index_mail_update_flags(struct mail *mail, enum modify_type modify_type,
--- a/src/lib-storage/index/index-mail.h	Sat Aug 11 14:27:40 2007 +0300
+++ b/src/lib-storage/index/index-mail.h	Sat Aug 11 14:35:36 2007 +0300
@@ -187,6 +187,6 @@
 struct istream *index_mail_cache_parse_init(struct mail *mail,
 					    struct istream *input);
 void index_mail_cache_parse_continue(struct mail *mail);
-void index_mail_cache_parse_deinit(struct mail *mail);
+void index_mail_cache_parse_deinit(struct mail *mail, time_t received_date);
 
 #endif
--- a/src/lib-storage/index/maildir/maildir-save.c	Sat Aug 11 14:27:40 2007 +0300
+++ b/src/lib-storage/index/maildir/maildir-save.c	Sat Aug 11 14:35:36 2007 +0300
@@ -427,36 +427,27 @@
 int maildir_save_finish(struct mail_save_context *_ctx)
 {
 	struct maildir_save_context *ctx = (struct maildir_save_context *)_ctx;
+	struct mail_storage *storage = &ctx->mbox->storage->storage;
 	struct utimbuf buf;
+	struct stat st;
 	const char *path;
 	int output_errno;
 
-	if (o_stream_flush(ctx->output) < 0) {
-		mail_storage_set_critical(&ctx->mbox->storage->storage,
-			"o_stream_flush(%s/%s) failed: %m",
-			ctx->tmpdir, ctx->file_last->basename);
-		ctx->failed = TRUE;
-	}
-
-	if (ctx->cur_dest_mail != NULL) {
-		index_mail_cache_parse_deinit(ctx->cur_dest_mail);
-		i_stream_unref(&ctx->input);
-	}
-
 	ctx->finished = TRUE;
 	if (ctx->failed && ctx->fd == -1) {
 		/* tmp file creation failed */
 		return -1;
 	}
 
-	/* remember the size in case we want to add it to filename */
-	ctx->file_last->size = ctx->output->offset;
-	ctx->file_last->vsize = ctx->cur_dest_mail == NULL ? (uoff_t)-1 :
-		mail_get_virtual_size(ctx->cur_dest_mail);
-
 	t_push();
 	path = t_strconcat(ctx->tmpdir, "/", ctx->file_last->basename, NULL);
 
+	if (o_stream_flush(ctx->output) < 0) {
+		mail_storage_set_critical(storage,
+			"o_stream_flush(%s) failed: %m", path);
+		ctx->failed = TRUE;
+	}
+
 	if (ctx->received_date != (time_t)-1) {
 		/* set the received_date by modifying mtime */
 		buf.actime = ioloop_time;
@@ -464,23 +455,51 @@
 
 		if (utime(path, &buf) < 0) {
 			ctx->failed = TRUE;
-			mail_storage_set_critical(&ctx->mbox->storage->storage,
+			mail_storage_set_critical(storage,
 						  "utime(%s) failed: %m", path);
 		}
+	} else if (ctx->fd != -1) {
+		if (fstat(ctx->fd, &st) == 0)
+			ctx->received_date = st.st_mtime;
+		else {
+			ctx->failed = TRUE;
+			mail_storage_set_critical(storage,
+						  "fstat(%s) failed: %m", path);
+		}
+	} else {
+		/* hardlinked */
+		if (stat(path, &st) == 0)
+			ctx->received_date = st.st_mtime;
+		else {
+			ctx->failed = TRUE;
+			mail_storage_set_critical(storage,
+						  "stat(%s) failed: %m", path);
+		}
 	}
 
+	if (ctx->cur_dest_mail != NULL) {
+		index_mail_cache_parse_deinit(ctx->cur_dest_mail,
+					      ctx->received_date);
+		i_stream_unref(&ctx->input);
+	}
+
+	/* remember the size in case we want to add it to filename */
+	ctx->file_last->size = ctx->output->offset;
+	ctx->file_last->vsize = ctx->cur_dest_mail == NULL ? (uoff_t)-1 :
+		mail_get_virtual_size(ctx->cur_dest_mail);
+
 	output_errno = ctx->output->stream_errno;
 	o_stream_destroy(&ctx->output);
 
 	if (!ctx->mbox->ibox.fsync_disable) {
 		if (fsync(ctx->fd) < 0) {
-			mail_storage_set_critical(&ctx->mbox->storage->storage,
+			mail_storage_set_critical(storage,
 						  "fsync(%s) failed: %m", path);
 			ctx->failed = TRUE;
 		}
 	}
 	if (close(ctx->fd) < 0) {
-		mail_storage_set_critical(&ctx->mbox->storage->storage,
+		mail_storage_set_critical(storage,
 					  "close(%s) failed: %m", path);
 		ctx->failed = TRUE;
 	}
@@ -491,16 +510,16 @@
 
 		/* delete the tmp file */
 		if (unlink(path) < 0 && errno != ENOENT) {
-			mail_storage_set_critical(&ctx->mbox->storage->storage,
+			mail_storage_set_critical(storage,
 				"unlink(%s) failed: %m", path);
 		}
 
 		errno = output_errno;
 		if (ENOSPACE(errno)) {
-			mail_storage_set_error(&ctx->mbox->storage->storage,
+			mail_storage_set_error(storage,
 				MAIL_ERROR_NOSPACE, MAIL_ERRSTR_NO_SPACE);
 		} else if (errno != 0) {
-			mail_storage_set_critical(&ctx->mbox->storage->storage,
+			mail_storage_set_critical(storage,
 				"write(%s) failed: %m", ctx->mbox->path);
 		}
 
--- a/src/lib-storage/index/mbox/mbox-save.c	Sat Aug 11 14:27:40 2007 +0300
+++ b/src/lib-storage/index/mbox/mbox-save.c	Sat Aug 11 14:35:36 2007 +0300
@@ -39,6 +39,7 @@
 	struct mail *mail;
 	uoff_t append_offset, mail_offset;
 	time_t orig_atime;
+	time_t received_date;
 
 	string_t *headers;
 	size_t space_end_idx;
@@ -465,6 +466,7 @@
 	ctx->eoh_input_offset = (uoff_t)-1;
 	ctx->eoh_offset = (uoff_t)-1;
 	ctx->last_char = '\n';
+	ctx->received_date = received_date;
 
 	if (write_from_line(ctx, received_date, from_envelope) < 0)
 		ctx->failed = TRUE;
@@ -611,7 +613,7 @@
 	}
 
 	if (ctx->mail != NULL)
-		index_mail_cache_parse_deinit(ctx->mail);
+		index_mail_cache_parse_deinit(ctx->mail, ctx->received_date);
 	if (ctx->input != NULL)
 		i_stream_destroy(&ctx->input);
 	if (ctx->body_output != NULL)