[dovecot-cvs] dovecot/src/lib-storage/index/mbox mbox-expunge.c,1.28,1.29 mbox-storage.c,1.60,1.61 mbox-storage.h,1.15,1.16

cras at procontrol.fi cras at procontrol.fi
Sat Jul 26 20:33:25 EEST 2003


Update of /home/cvs/dovecot/src/lib-storage/index/mbox
In directory danu:/tmp/cvs-serv28560/lib-storage/index/mbox

Modified Files:
	mbox-expunge.c mbox-storage.c mbox-storage.h 
Log Message:
API change for expunging messages. Not exactly what I wanted, but good
enough.



Index: mbox-expunge.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-expunge.c,v
retrieving revision 1.28
retrieving revision 1.29
diff -u -d -r1.28 -r1.29
--- mbox-expunge.c	21 Jul 2003 14:35:39 -0000	1.28
+++ mbox-expunge.c	26 Jul 2003 16:33:22 -0000	1.29
@@ -1,4 +1,4 @@
-/* Copyright (C) 2002 Timo Sirainen */
+/* Copyright (C) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
 #include "istream.h"
@@ -6,179 +6,204 @@
 #include "mbox-index.h"
 #include "mbox-storage.h"
 #include "mbox-lock.h"
+#include "index-expunge.h"
 
 #include <fcntl.h>
 #include <unistd.h>
 
-static int expunge_real(struct index_mailbox *ibox,
-			struct mail_index_record *rec, unsigned int seq,
-			struct istream *input, struct ostream *output,
-			int notify)
-{
-	struct mail_index_record *first_rec, *last_rec;
-	uoff_t offset, hdr_size, body_size;
-	uoff_t end_offset, from_offset, copy_size, old_limit;
-	const unsigned char *data;
-	size_t size;
-	unsigned int first_seq, last_seq;
-	int expunges, skip_next, deleted, failed;
+struct mbox_expunge_context {
+	struct mail_expunge_context *ctx;
 
-	if (seq == 1)
-		end_offset = 0;
-	else {
-		/* we need to find offset to beginning of From-line.
-		   not the fastest way maybe, but easiest.. */
-		rec = ibox->index->lookup(ibox->index, seq-1);
-		
-		if (!mbox_mail_get_location(ibox->index, rec, &offset,
-					    &hdr_size, &body_size))
-			return FALSE;
-		end_offset = offset + hdr_size + body_size;
+        struct index_mailbox *ibox;
+	struct istream *input;
+	struct ostream *output;
+	int failed, expunges;
 
-		/* get back to the deleted record */
-		rec = ibox->index->next(ibox->index, rec);
-	}
+	uoff_t from_offset, move_offset;
+};
 
-	old_limit = input->v_limit;
+struct mail_expunge_context *
+mbox_storage_expunge_init(struct mailbox *box,
+			  enum mail_fetch_field wanted_fields, int expunge_all)
+{
+	struct index_mailbox *ibox = (struct index_mailbox *) box;
+	struct mbox_expunge_context *ctx;
+	struct mail_expunge_context *mctx;
+	struct istream *input;
 
-	first_rec = last_rec = NULL;
-	first_seq = last_seq = 0;
+	mctx = index_storage_expunge_init(box, wanted_fields, expunge_all);
+	if (mctx == NULL)
+		return NULL;
 
-	expunges = FALSE; skip_next = FALSE;
-	while (rec != NULL) {
-		if (!mbox_mail_get_location(ibox->index, rec, &offset,
-					    &hdr_size, &body_size))
-			return FALSE;
+	/* mbox must be already opened, synced and locked at this point.
+	   we just want the istream. */
+	input = mbox_get_stream(ibox->index, 0, MAIL_LOCK_EXCLUSIVE);
+	if (input == NULL)
+		return NULL;
 
-		from_offset = end_offset;
-		end_offset = offset + hdr_size + body_size;
+	i_assert(ibox->index->mbox_sync_counter ==
+		 ibox->index->mbox_lock_counter);
 
-		deleted = (rec->msg_flags & MAIL_DELETED) != 0;
-		if (deleted) {
-			if (first_rec == NULL) {
-				first_rec = rec;
-				first_seq = seq;
-			}
-			last_rec = rec;
-			last_seq = seq;
+	ctx = i_new(struct mbox_expunge_context, 1);
+	ctx->ctx = mctx;
+	ctx->ibox = ibox;
+	ctx->input = input;
+	ctx->output = o_stream_create_file(ibox->index->mbox_fd, default_pool,
+					   4096, FALSE);
+	ctx->from_offset = (uoff_t)-1;
+	ctx->move_offset = (uoff_t)-1;
+	o_stream_set_blocking(ctx->output, 60000, NULL, NULL);
+	return (struct mail_expunge_context *) ctx;
+}
 
-			if (!expunges) {
-				/* first expunged record, seek to position
-				   where we want to begin writing */
-				if (o_stream_seek(output, from_offset) < 0)
-					return FALSE;
-				expunges = TRUE;
-			}
-		} else if (first_rec != NULL) {
-			if (!index_expunge_mails(ibox, first_rec, last_rec,
-						 first_seq, last_seq, notify))
-				return FALSE;
-			first_rec = NULL;
+static int mbox_move_data(struct mbox_expunge_context *ctx)
+{
+	const unsigned char *data;
+	size_t size;
+	uoff_t old_limit;
+	int failed;
 
-			rec = ibox->index->lookup(ibox->index, first_seq);
-			seq = first_seq;
-			skip_next = TRUE;
-		}
+	i_assert(ctx->input->v_offset <= ctx->move_offset);
+	i_stream_skip(ctx->input, ctx->move_offset - ctx->input->v_offset);
 
-		if (skip_next)
-			skip_next = FALSE;
-		else {
-			rec = ibox->index->next(ibox->index, rec);
-			seq++;
-		}
+	if (ctx->output->offset == 0) {
+		/* we're writing to beginning of mbox, so we
+		   don't want the [\r]\n there */
+		(void)i_stream_read_data(ctx->input, &data, &size, 1);
+		if (size > 0 && data[0] == '\n')
+			i_stream_skip(ctx->input, 1);
+		else if (size > 1 && data[0] == '\r' &&
+			 data[1] == '\n')
+			i_stream_skip(ctx->input, 2);
+	}
 
-		if (expunges && !deleted) {
-			/* seek to wanted input position, and copy
-			   this messages */
-			i_assert(input->v_offset <= from_offset);
-			i_stream_skip(input, from_offset - input->v_offset);
+	old_limit = ctx->input->v_limit;
+	i_stream_set_read_limit(ctx->input, ctx->from_offset);
+	failed = o_stream_send_istream(ctx->output, ctx->input) < 0;
+	i_stream_set_read_limit(ctx->input, old_limit);
 
-			if (output->offset == 0) {
-				/* we're writing to beginning of mbox, so we
-				   don't want the [\r]\n there */
-				(void)i_stream_read_data(input, &data,
-							 &size, 1);
-				if (size > 0 && data[0] == '\n')
-					i_stream_skip(input, 1);
-				else if (size > 1 && data[0] == '\r' &&
-					 data[1] == '\n')
-					i_stream_skip(input, 2);
-			}
+	if (failed || ctx->input->v_offset != ctx->from_offset)
+		return FALSE;
+	return TRUE;
+}
 
-			i_stream_set_read_limit(input, end_offset);
-			failed = o_stream_send_istream(output, input) < 0;
-			i_stream_set_read_limit(input, old_limit);
+int mbox_storage_expunge_deinit(struct mail_expunge_context *_ctx)
+{
+	struct mbox_expunge_context *ctx = (struct mbox_expunge_context *) _ctx;
+	int failed = ctx->failed;
 
-			if (failed || input->v_offset != end_offset)
-				return FALSE;
+	if (ctx->expunges) {
+		if (!failed && ctx->move_offset != (uoff_t)-1) {
+			ctx->from_offset = ctx->input->v_limit;
+			if (!mbox_move_data(ctx))
+				failed = TRUE;
+		} else if (failed && ctx->output->offset > 0) {
+			/* we moved some of the data. move the rest as well
+			   so there won't be invalid holes in mbox file */
+			(void)o_stream_send_istream(ctx->output, ctx->input);
 		}
-	}
 
-	if (first_rec != NULL) {
-		if (!index_expunge_mails(ibox, first_rec, last_rec,
-					 first_seq, last_seq, notify))
-			return FALSE;
+		if (ftruncate(ctx->ibox->index->mbox_fd,
+			      (off_t)ctx->output->offset) < 0) {
+			mail_storage_set_error(ctx->ibox->box.storage,
+				"ftruncate() failed for mbox file %s: %m",
+				ctx->ibox->index->mailbox_path);
+			failed = TRUE;
+		}
 	}
 
-	i_stream_skip(input, end_offset - input->v_offset);
-
-	/* copy the rest as well, should be only \n but someone might
-	   as well just appended more data.. but if we've deleted all mail,
-	   don't write the only \n there. */
-	copy_size = input->v_size - input->v_offset;
-	if (output->offset == 0 && copy_size == 1)
-		return TRUE;
+	if (!index_storage_expunge_deinit(ctx->ctx))
+		failed = TRUE;
 
-	return o_stream_send_istream(output, input) >= 0;
+	o_stream_unref(ctx->output);
+	i_free(ctx);
+	return !failed;
 }
 
-int mbox_expunge_locked(struct index_mailbox *ibox, int notify)
+static int get_from_offset(struct mail_index *index,
+			   struct mail_index_record *rec, uoff_t *offset_r)
 {
-	struct mail_index_record *rec;
-	struct istream *input;
-	struct ostream *output;
-	unsigned int seq;
-	int failed;
+	uoff_t offset, hdr_size, body_size;
 
-	if (!index_expunge_seek_first(ibox, &seq, &rec))
+	if (!mbox_mail_get_location(index, rec, &offset,
+				    &hdr_size, &body_size))
 		return FALSE;
 
-	if (rec == NULL) {
-		/* no deleted messages */
-		return TRUE;
+	*offset_r = offset + hdr_size + body_size;
+	return TRUE;
+}
+
+struct mail *mbox_storage_expunge_fetch_next(struct mail_expunge_context *_ctx)
+{
+	struct mbox_expunge_context *ctx =
+		(struct mbox_expunge_context *) _ctx;
+	struct mail_expunge_context *mctx = ctx->ctx;
+	struct mail_index *index = ctx->ibox->index;
+
+	if (mctx->rec == NULL)
+		return NULL;
+
+	if (mctx->fetch_next) {
+                mctx->fetch_next = FALSE;
+		do {
+			if (!get_from_offset(index, mctx->rec,
+					     &ctx->from_offset)) {
+				ctx->failed = TRUE;
+				return NULL;
+			}
+
+			mctx->seq++;
+			mctx->rec = index->next(index, mctx->rec);
+			if (mctx->rec == NULL)
+				return NULL;
+		} while ((mctx->rec->msg_flags & MAIL_DELETED) == 0 &&
+			 !mctx->expunge_all);
 	}
 
-	/* mbox must be already opened, synced and locked at this point.
-	   we just want the istream. */
-	input = mbox_get_stream(ibox->index, 0, MAIL_LOCK_EXCLUSIVE);
-	if (input == NULL)
-		return FALSE;
+	return index_storage_expunge_fetch_next(ctx->ctx);
+}
 
-	i_assert(ibox->index->mbox_sync_counter ==
-		 ibox->index->mbox_lock_counter);
+static int get_prev_from_offset(struct mbox_expunge_context *ctx,
+				unsigned int seq)
+{
+	struct mail_index_record *rec;
 
-	t_push();
-	output = o_stream_create_file(ibox->index->mbox_fd, data_stack_pool,
-				      4096, FALSE);
-	o_stream_set_blocking(output, 60000, NULL, NULL);
+	if (seq == 1)
+		ctx->from_offset = 0;
+	else {
+		rec = ctx->ibox->index->lookup(ctx->ibox->index, seq-1);
 
-	failed = !expunge_real(ibox, rec, seq, input, output, notify);
+		if (!get_from_offset(ctx->ibox->index, rec, &ctx->from_offset))
+			return FALSE;
+	}
 
-	if (failed && output->offset > 0) {
-		/* we moved some of the data. move the rest as well so there
-		   won't be invalid holes in mbox file */
-		(void)o_stream_send_istream(output, input);
+	return TRUE;
+}
+
+int mbox_storage_expunge(struct mail *mail, struct mail_expunge_context *_ctx,
+			 unsigned int *seq_r, int notify)
+{
+	struct mbox_expunge_context *ctx = (struct mbox_expunge_context *) _ctx;
+	struct index_mail *imail = (struct index_mail *) mail;
+
+	if (ctx->from_offset == (uoff_t)-1) {
+		if (!get_prev_from_offset(ctx, imail->data.idx_seq))
+			return FALSE;
 	}
 
-	if (ftruncate(ibox->index->mbox_fd, (off_t)output->offset) < 0) {
-		mail_storage_set_error(ibox->box.storage, "ftruncate() failed "
-				       "for mbox file %s: %m",
-				       ibox->index->mailbox_path);
-		failed = TRUE;
+	if (!ctx->expunges) {
+		/* first expunged message */
+		if (o_stream_seek(ctx->output, ctx->from_offset) < 0)
+			return FALSE;
+		ctx->expunges = TRUE;
+	} else if (ctx->move_offset != ctx->from_offset) {
+		if (!mbox_move_data(ctx))
+			return FALSE;
 	}
 
-	o_stream_unref(output);
-	t_pop();
+	if (!get_from_offset(ctx->ibox->index, imail->data.rec,
+			     &ctx->move_offset))
+		return FALSE;
 
-	return !failed;
+	return index_storage_expunge(mail, ctx->ctx, seq_r, notify);
 }

Index: mbox-storage.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-storage.c,v
retrieving revision 1.60
retrieving revision 1.61
diff -u -d -r1.60 -r1.61
--- mbox-storage.c	23 Jul 2003 02:55:12 -0000	1.60
+++ mbox-storage.c	26 Jul 2003 16:33:22 -0000	1.61
@@ -319,6 +319,11 @@
 	return t_strconcat(storage->dir, "/", name, NULL);
 }
 
+static void mbox_mail_init(struct index_mail *mail)
+{
+	mail->mail.expunge = mbox_storage_expunge;
+}
+
 static struct mailbox *mbox_open(struct mail_storage *storage, const char *name,
 				 enum mailbox_open_flags flags)
 {
@@ -349,7 +354,7 @@
 	ibox = index_storage_mailbox_init(storage, &mbox_mailbox, index,
 					  name, flags);
 	if (ibox != NULL)
-		ibox->expunge_locked = mbox_expunge_locked;
+		ibox->mail_init = mbox_mail_init;
 	return (struct mailbox *) ibox;
 }
 
@@ -780,7 +785,6 @@
 	index_storage_get_status,
 	index_storage_sync,
 	mbox_storage_auto_sync,
-	index_storage_expunge,
 	index_storage_fetch_init,
 	index_storage_fetch_deinit,
 	index_storage_fetch_next,
@@ -795,6 +799,9 @@
 	mbox_storage_save_next,
 	index_storage_copy_init,
 	index_storage_copy_deinit,
+	mbox_storage_expunge_init,
+	mbox_storage_expunge_deinit,
+	mbox_storage_expunge_fetch_next,
 	mail_storage_is_inconsistency_error,
 
 	FALSE,

Index: mbox-storage.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-storage/index/mbox/mbox-storage.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- mbox-storage.h	19 Feb 2003 19:55:27 -0000	1.15
+++ mbox-storage.h	26 Jul 2003 16:33:22 -0000	1.16
@@ -20,7 +20,13 @@
 int mbox_list_mailbox_deinit(struct mailbox_list_context *ctx);
 struct mailbox_list *mbox_list_mailbox_next(struct mailbox_list_context *ctx);
 
-int mbox_expunge_locked(struct index_mailbox *ibox, int notify);
+struct mail_expunge_context *
+mbox_storage_expunge_init(struct mailbox *box,
+			  enum mail_fetch_field wanted_fields, int expunge_all);
+int mbox_storage_expunge_deinit(struct mail_expunge_context *ctx);
+struct mail *mbox_storage_expunge_fetch_next(struct mail_expunge_context *ctx);
+int mbox_storage_expunge(struct mail *mail, struct mail_expunge_context *ctx,
+			 unsigned int *seq_r, int notify);
 
 int mbox_is_valid_mask(const char *mask);
 



More information about the dovecot-cvs mailing list