dovecot-2.2: Added mailbox { autoexpunge } setting.

dovecot at dovecot.org dovecot at dovecot.org
Fri Nov 27 11:59:31 UTC 2015


details:   http://hg.dovecot.org/dovecot-2.2/rev/82e6a3baa001
changeset: 19421:82e6a3baa001
user:      Timo Sirainen <tss at iki.fi>
date:      Fri Nov 27 13:59:22 2015 +0200
description:
Added mailbox { autoexpunge } setting.
This can be used to automatically expunge mails from specified mailboxes
after they're old enough. The expunges are done when the user is being
deinitialized. mailbox_list_index=yes should be enabled to have the best
performance with this setting.

Example:

namespace inbox {
  mailbox Spam {
    auto = create
    special_use = \Junk
    autoexpunge = 30d
  }
}

diffstat:

 src/lib-storage/Makefile.am                      |    1 +
 src/lib-storage/list/mailbox-list-index-status.c |  117 ++++++++++++++++++++++-
 src/lib-storage/list/mailbox-list-index.h        |    2 +-
 src/lib-storage/mail-autoexpunge.c               |   93 ++++++++++++++++++
 src/lib-storage/mail-autoexpunge.h               |    6 +
 src/lib-storage/mail-storage-private.h           |    5 +
 src/lib-storage/mail-storage-settings.c          |    4 +-
 src/lib-storage/mail-storage-settings.h          |    1 +
 src/lib-storage/mail-storage.h                   |   11 +-
 src/lib-storage/mail-user.c                      |    3 +
 10 files changed, 237 insertions(+), 6 deletions(-)

diffs (truncated from 415 to 300 lines):

diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/Makefile.am
--- a/src/lib-storage/Makefile.am	Fri Nov 27 13:06:01 2015 +0200
+++ b/src/lib-storage/Makefile.am	Fri Nov 27 13:59:22 2015 +0200
@@ -24,6 +24,7 @@
 	fail-mailbox.c \
 	fail-mail.c \
 	mail.c \
+	mail-autoexpunge.c \
 	mail-copy.c \
 	mail-error.c \
 	mail-namespace.c \
diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/list/mailbox-list-index-status.c
--- a/src/lib-storage/list/mailbox-list-index-status.c	Fri Nov 27 13:06:01 2015 +0200
+++ b/src/lib-storage/list/mailbox-list-index-status.c	Fri Nov 27 13:59:22 2015 +0200
@@ -15,11 +15,13 @@
 	guid_128_t guid;
 	uint32_t seq;
 	struct mailbox_index_vsize vsize;
+	uint32_t first_uid;
 
 	bool rec_changed;
 	bool msgs_changed;
 	bool hmodseq_changed;
 	bool vsize_changed;
+	bool first_saved_changed;
 };
 
 struct index_list_storage_module index_list_storage_module =
@@ -268,6 +270,30 @@
 }
 
 static int
+index_list_get_cached_first_saved(struct mailbox *box,
+				  struct mailbox_index_first_saved *first_saved_r)
+{
+	struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list);
+	struct mail_index_view *view;
+	const void *data;
+	bool expunged;
+	uint32_t seq;
+	int ret;
+
+	memset(first_saved_r, 0, sizeof(*first_saved_r));
+
+	if ((ret = index_list_open_view(box, &view, &seq)) <= 0)
+		return ret;
+
+	mail_index_lookup_ext(view, seq, ilist->first_saved_ext_id,
+			      &data, &expunged);
+	if (data != NULL)
+		memcpy(first_saved_r, data, sizeof(*first_saved_r));
+	mail_index_view_close(&view);
+	return first_saved_r->timestamp != 0 ? 1 : 0;
+}
+
+static int
 index_list_try_get_metadata(struct mailbox *box,
 			    enum mailbox_metadata_items items,
 			    struct mailbox_metadata *metadata_r)
@@ -286,7 +312,8 @@
 	/* see if we have a chance of fulfilling this without opening
 	   the mailbox. */
 	noncached_items = items & ~(MAILBOX_METADATA_GUID |
-				    MAILBOX_METADATA_VIRTUAL_SIZE);
+				    MAILBOX_METADATA_VIRTUAL_SIZE |
+				    MAILBOX_METADATA_FIRST_SAVE_DATE);
 	if ((noncached_items & MAILBOX_METADATA_PHYSICAL_SIZE) != 0 &&
 	    box->mail_vfuncs->get_physical_size ==
 	    box->mail_vfuncs->get_virtual_size)
@@ -306,6 +333,15 @@
 		if ((items & MAILBOX_METADATA_PHYSICAL_SIZE) != 0)
 			metadata_r->physical_size = metadata_r->virtual_size;
 	}
+	if ((items & MAILBOX_METADATA_FIRST_SAVE_DATE) != 0) {
+		struct mailbox_index_first_saved first_saved;
+
+		if ((ret = index_list_get_cached_first_saved(box, &first_saved)) <= 0)
+			return ret;
+		metadata_r->first_save_date =
+			first_saved.timestamp == (uint32_t)-1 ? (time_t)-1 :
+			first_saved.timestamp;
+	}
 	return 1;
 }
 
@@ -386,6 +422,33 @@
 	return TRUE;
 }
 
+static void
+index_list_first_saved_update_changes(struct mailbox *box,
+				      struct mail_index_view *list_view,
+				      struct index_list_changes *changes)
+{
+	struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list);
+	struct mailbox_index_first_saved first_saved;
+	const void *data;
+	bool expunged;
+
+	mail_index_lookup_ext(list_view, changes->seq,
+			      ilist->first_saved_ext_id, &data, &expunged);
+	if (data == NULL)
+		memset(&first_saved, 0, sizeof(first_saved));
+	else
+		memcpy(&first_saved, data, sizeof(first_saved));
+	if (mail_index_view_get_messages_count(box->view) > 0)
+		mail_index_lookup_uid(box->view, 1, &changes->first_uid);
+	if (first_saved.uid == 0 && first_saved.timestamp == 0) {
+		/* first time setting this */
+		changes->first_saved_changed = TRUE;
+	} else {
+		changes->first_saved_changed =
+			changes->first_uid != first_saved.uid;
+	}
+}
+
 static bool
 index_list_has_changed(struct mailbox *box, struct mail_index_view *list_view,
 		       struct index_list_changes *changes)
@@ -428,12 +491,57 @@
 	}
 	if (memcmp(&old_vsize, &changes->vsize, sizeof(old_vsize)) != 0)
 		changes->vsize_changed = TRUE;
+	index_list_first_saved_update_changes(box, list_view, changes);
 
 	return changes->rec_changed || changes->msgs_changed ||
-		changes->hmodseq_changed || changes->vsize_changed;
+		changes->hmodseq_changed || changes->vsize_changed ||
+		changes->first_saved_changed;
 }
 
 static void
+index_list_update_first_saved(struct mailbox *box,
+			      struct mail_index_transaction *list_trans,
+			      const struct index_list_changes *changes)
+{
+	struct mailbox_list_index *ilist = INDEX_LIST_CONTEXT(box->list);
+	struct mailbox_transaction_context *t;
+	struct mail *mail;
+	struct mailbox_index_first_saved first_saved;
+	uint32_t seq, messages_count;
+	time_t save_date;
+	int ret = 0;
+
+	memset(&first_saved, 0, sizeof(first_saved));
+	first_saved.uid = changes->first_uid;
+	first_saved.timestamp = (uint32_t)-1;
+
+	if (changes->first_uid != 0) {
+		t = mailbox_transaction_begin(box, 0);
+		mail = mail_alloc(t, MAIL_FETCH_SAVE_DATE, NULL);
+		messages_count = mail_index_view_get_messages_count(box->view);
+		for (seq = 1; seq <= messages_count; seq++) {
+			mail_set_seq(mail, seq);
+			if (mail_get_save_date(mail, &save_date) == 0) {
+				first_saved.timestamp = save_date;
+				break;
+			}
+			if (mailbox_get_last_mail_error(box) != MAIL_ERROR_EXPUNGED) {
+				ret = -1;
+				break;
+			}
+		}
+		mail_free(&mail);
+		(void)mailbox_transaction_commit(&t);
+	}
+	if (ret == 0) {
+		mail_index_update_ext(list_trans, changes->seq,
+				      ilist->first_saved_ext_id,
+				      &first_saved, NULL);
+	}
+}
+
+
+static void
 index_list_update(struct mailbox *box, struct mail_index_view *list_view,
 		  struct mail_index_transaction *list_trans,
 		  const struct index_list_changes *changes)
@@ -480,6 +588,8 @@
 				      ilist->vsize_ext_id,
 				      &changes->vsize, NULL);
 	}
+	if (changes->first_saved_changed)
+		index_list_update_first_saved(box, list_trans, changes);
 }
 
 static int index_list_update_mailbox(struct mailbox *box)
@@ -705,4 +815,7 @@
 	ilist->vsize_ext_id =
 		mail_index_ext_register(ilist->index, "vsize", 0,
 			sizeof(struct mailbox_index_vsize), sizeof(uint64_t));
+	ilist->first_saved_ext_id =
+		mail_index_ext_register(ilist->index, "1saved", 0,
+			sizeof(struct mailbox_index_first_saved), sizeof(uint32_t));
 }
diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/list/mailbox-list-index.h
--- a/src/lib-storage/list/mailbox-list-index.h	Fri Nov 27 13:06:01 2015 +0200
+++ b/src/lib-storage/list/mailbox-list-index.h	Fri Nov 27 13:59:22 2015 +0200
@@ -89,7 +89,7 @@
 	const char *path;
 	struct mail_index *index;
 	uint32_t ext_id, msgs_ext_id, hmodseq_ext_id, subs_hdr_ext_id;
-	uint32_t vsize_ext_id;
+	uint32_t vsize_ext_id, first_saved_ext_id;
 	struct timeval last_refresh_timeval;
 
 	pool_t mailbox_pool;
diff -r db90e76f44dc -r 82e6a3baa001 src/lib-storage/mail-autoexpunge.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lib-storage/mail-autoexpunge.c	Fri Nov 27 13:59:22 2015 +0200
@@ -0,0 +1,93 @@
+/* Copyright (c) 2015 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "ioloop.h"
+#include "mail-storage-private.h"
+#include "mail-namespace.h"
+#include "mail-user.h"
+#include "mail-autoexpunge.h"
+
+static int mailbox_autoexpunge(struct mailbox *box, time_t expire_time)
+{
+	struct mailbox_transaction_context *t;
+	struct mail *mail;
+	struct mailbox_metadata metadata;
+	const struct mail_index_header *hdr;
+	uint32_t seq;
+	time_t timestamp;
+	int ret = 0;
+
+	/* first try to check quickly from mailbox list index if we should
+	   bother opening this mailbox. */
+	if (mailbox_get_metadata(box, MAILBOX_METADATA_FIRST_SAVE_DATE,
+				 &metadata) == 0) {
+		if (metadata.first_save_date == (time_t)-1 ||
+		    metadata.first_save_date > expire_time)
+			return 0;
+	}
+
+	if (mailbox_sync(box, MAILBOX_SYNC_FLAG_FAST) < 0) {
+		if (mailbox_get_last_mail_error(box) == MAIL_ERROR_NOTFOUND) {
+			/* autocreated mailbox doesn't exist yet */
+			return 0;
+		}
+		return -1;
+	}
+
+	t = mailbox_transaction_begin(box, 0);
+	mail = mail_alloc(t, 0, NULL);
+
+	hdr = mail_index_get_header(box->view);
+	for (seq = 1; seq <= hdr->messages_count; seq++) {
+		mail_set_seq(mail, seq);
+		if (mail_get_save_date(mail, &timestamp) == 0) {
+			if (timestamp > expire_time)
+				break;
+			mail_expunge(mail);
+		} else if (mailbox_get_last_mail_error(box) == MAIL_ERROR_EXPUNGED) {
+			/* already expunged */
+		} else {
+			/* failed */
+			ret = -1;
+			break;
+		}
+	}
+	mail_free(&mail);
+	if (mailbox_transaction_commit(&t) < 0)
+		ret = -1;
+	return ret;
+}
+
+static void mail_namespace_autoexpunge(struct mail_namespace *ns)
+{
+	struct mailbox_settings *const *box_set;
+	struct mailbox *box;
+	time_t expire_time;
+
+	if (!array_is_created(&ns->set->mailboxes))
+		return;
+
+	array_foreach(&ns->set->mailboxes, box_set) {
+		if ((*box_set)->autoexpunge == 0 ||
+		    ioloop_time < (*box_set)->autoexpunge)
+			continue;
+		expire_time = ioloop_time - (*box_set)->autoexpunge;
+		box = mailbox_alloc(ns->list, (*box_set)->name, 0);
+		if (mailbox_autoexpunge(box, expire_time) < 0) {
+			i_error("Failed to autoexpunge mailbox '%s': %s",
+				mailbox_get_vname(box),
+				mailbox_get_last_error(box, NULL));
+		}
+		mailbox_free(&box);
+	}
+}
+
+void mail_user_autoexpunge(struct mail_user *user)
+{
+	struct mail_namespace *ns;
+
+	for (ns = user->namespaces; ns != NULL; ns = ns->next) {


More information about the dovecot-cvs mailing list