changeset 5633:fbb4bdbbf374 HEAD

Added mbox snarf plugin to move mails from /var/spool/mail to ~/mbox if it exists.
author Timo Sirainen <tss@iki.fi>
date Thu, 17 May 2007 20:25:26 +0300
parents 2ed5abe3aaef
children 69ca46114593
files configure.in src/plugins/Makefile.am src/plugins/mbox-snarf/.cvsignore src/plugins/mbox-snarf/Makefile.am src/plugins/mbox-snarf/mbox-snarf-plugin.c src/plugins/mbox-snarf/mbox-snarf-plugin.h
diffstat 6 files changed, 240 insertions(+), 1 deletions(-) [+]
line wrap: on
line diff
--- a/configure.in	Thu May 17 16:58:55 2007 +0300
+++ b/configure.in	Thu May 17 20:25:26 2007 +0300
@@ -1939,6 +1939,7 @@
 src/plugins/fts-squat/Makefile
 src/plugins/lazy-expunge/Makefile
 src/plugins/mail-log/Makefile
+src/plugins/mbox-snarf/Makefile
 src/plugins/quota/Makefile
 src/plugins/imap-quota/Makefile
 src/plugins/trash/Makefile
--- a/src/plugins/Makefile.am	Thu May 17 16:58:55 2007 +0300
+++ b/src/plugins/Makefile.am	Thu May 17 20:25:26 2007 +0300
@@ -7,6 +7,6 @@
 endif
 
 SUBDIRS = \
-	acl convert expire fts fts-squat lazy-expunge mail-log \
+	acl convert expire fts fts-squat lazy-expunge mail-log mbox-snarf \
 	quota imap-quota trash \
 	$(ZLIB) $(FTS_LUCENE)
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/mbox-snarf/.cvsignore	Thu May 17 20:25:26 2007 +0300
@@ -0,0 +1,8 @@
+*.la
+*.lo
+*.o
+.deps
+.libs
+Makefile
+Makefile.in
+so_locations
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/mbox-snarf/Makefile.am	Thu May 17 20:25:26 2007 +0300
@@ -0,0 +1,23 @@
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-mail \
+	-I$(top_srcdir)/src/lib-index \
+	-I$(top_srcdir)/src/lib-storage
+
+lib20_mbox_snarf_plugin_la_LDFLAGS = -module -avoid-version
+
+module_LTLIBRARIES = \
+	lib20_mbox_snarf_plugin.la
+
+lib20_mbox_snarf_plugin_la_SOURCES = \
+	mbox-snarf-plugin.c
+
+noinst_HEADERS = \
+	mbox-snarf-plugin.h
+
+install-exec-local:
+	for d in imap pop3; do \
+	  $(mkdir_p) $(DESTDIR)$(moduledir)/$$d; \
+	  rm -f $(DESTDIR)$(moduledir)/$$d/lib20_mbox_snarf_plugin.so; \
+	  $(LN_S) ../lib20_mbox_snarf_plugin.so $(DESTDIR)$(moduledir)/$$d; \
+	done
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/mbox-snarf/mbox-snarf-plugin.c	Thu May 17 20:25:26 2007 +0300
@@ -0,0 +1,200 @@
+/* Copyright (C) 2007 Timo Sirainen */
+
+#include "lib.h"
+#include "array.h"
+#include "home-expand.h"
+#include "mail-search.h"
+#include "mail-storage-private.h"
+#include "mbox-snarf-plugin.h"
+
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#define MBOX_SNARF_CONTEXT(obj) \
+	MODULE_CONTEXT(obj, mbox_snarf_storage_module)
+
+struct mbox_snarf_mail_storage {
+	union mail_storage_module_context module_ctx;
+
+	const char *snarf_inbox_path;
+	bool open_spool_inbox;
+};
+
+struct mbox_snarf_mailbox {
+	union mailbox_module_context module_ctx;
+
+	struct mailbox *spool_mbox;
+};
+
+const char *mbox_snarf_plugin_version = PACKAGE_VERSION;
+
+static void (*mbox_snarf_next_hook_mail_storage_created)
+	(struct mail_storage *storage);
+
+static MODULE_CONTEXT_DEFINE_INIT(mbox_snarf_storage_module,
+				  &mail_storage_module_register);
+
+static int sync_mailbox(struct mailbox *box)
+{
+	struct mailbox_sync_context *ctx;
+        struct mailbox_sync_rec sync_rec;
+
+	ctx = mailbox_sync_init(box, MAILBOX_SYNC_FLAG_FULL_READ);
+	while (mailbox_sync_next(ctx, &sync_rec) > 0)
+		;
+	return mailbox_sync_deinit(&ctx, 0, NULL);
+}
+
+static int mbox_snarf(struct mailbox *srcbox, struct mailbox *destbox)
+{
+	struct mail_search_arg search_arg;
+	struct mail_search_context *search_ctx;
+        struct mailbox_transaction_context *src_trans, *dest_trans;
+	struct mail *mail;
+	int ret;
+
+	if (sync_mailbox(srcbox) < 0)
+		return -1;
+
+	memset(&search_arg, 0, sizeof(search_arg));
+	search_arg.type = SEARCH_ALL;
+
+	src_trans = mailbox_transaction_begin(srcbox, 0);
+	dest_trans = mailbox_transaction_begin(destbox,
+					MAILBOX_TRANSACTION_FLAG_EXTERNAL);
+	search_ctx = mailbox_search_init(src_trans, NULL, &search_arg, NULL);
+
+	mail = mail_alloc(src_trans, MAIL_FETCH_STREAM_HEADER |
+			  MAIL_FETCH_STREAM_BODY, NULL);
+	while ((ret = mailbox_search_next(search_ctx, mail)) > 0) {
+		if (mail->expunged)
+			continue;
+
+		if (mailbox_copy(dest_trans, mail, 0, NULL, NULL) < 0) {
+			if (!mail->expunged) {
+				ret = -1;
+				break;
+			}
+		}
+		mail_expunge(mail);
+	}
+	mail_free(&mail);
+
+	if (mailbox_search_deinit(&search_ctx) < 0)
+		ret = -1;
+
+	/* commit the copied messages to the destination mailbox. if we crash
+	   between that and between expunging the messages from the source
+	   mailbox, we're left with duplicates. */
+	if (ret < 0)
+		mailbox_transaction_rollback(&dest_trans);
+	else if (mailbox_transaction_commit(&dest_trans, 0) < 0)
+		ret = -1;
+
+	if (ret < 0)
+		mailbox_transaction_rollback(&src_trans);
+	else {
+		if (mailbox_transaction_commit(&src_trans, 0) < 0)
+			ret = -1;
+	}
+	return ret;
+}
+
+static struct mailbox_sync_context *
+mbox_snarf_sync_init(struct mailbox *box, enum mailbox_sync_flags flags)
+{
+	struct mbox_snarf_mail_storage *mstorage =
+		MBOX_SNARF_CONTEXT(box->storage);
+	struct mbox_snarf_mailbox *mbox = MBOX_SNARF_CONTEXT(box);
+
+	if (mbox->spool_mbox == NULL) {
+		/* try to open the spool mbox */
+		mstorage->open_spool_inbox = TRUE;
+		mbox->spool_mbox =
+			mailbox_open(box->storage, "INBOX", NULL,
+				     MAILBOX_OPEN_KEEP_RECENT |
+				     MAILBOX_OPEN_NO_INDEX_FILES);
+		mstorage->open_spool_inbox = FALSE;
+	}
+
+	if (mbox->spool_mbox != NULL)
+		mbox_snarf(mbox->spool_mbox, box);
+
+	return mbox->module_ctx.super.sync_init(box, flags);
+}
+
+static struct mailbox *
+mbox_snarf_mailbox_open(struct mail_storage *storage, const char *name,
+			struct istream *input, enum mailbox_open_flags flags)
+{
+	struct mbox_snarf_mail_storage *mstorage =
+		MBOX_SNARF_CONTEXT(storage);
+	struct mailbox *box;
+	struct mbox_snarf_mailbox *mbox;
+	struct stat st;
+	enum mail_storage_flags old_flags = storage->flags;
+	bool use_snarfing = FALSE;
+
+	if (strcasecmp(name, "INBOX") == 0 && !mstorage->open_spool_inbox) {
+		if (stat(mstorage->snarf_inbox_path, &st) == 0) {
+			/* use ~/mbox as the INBOX */
+			name = mstorage->snarf_inbox_path;
+			use_snarfing = TRUE;
+			storage->flags |= MAIL_STORAGE_FLAG_FULL_FS_ACCESS;
+		} else if (errno != ENOENT) {
+			mail_storage_set_critical(storage,
+						  "stat(%s) failed: %m",
+						  mstorage->snarf_inbox_path);
+		}
+	}
+
+	box = mstorage->module_ctx.super.
+		mailbox_open(storage, name, input, flags);
+	storage->flags = old_flags;
+
+	if (box == NULL || !use_snarfing)
+		return box;
+
+	mbox = p_new(box->pool, struct mbox_snarf_mailbox, 1);
+	mbox->module_ctx.super = box->v;
+
+	box->v.sync_init = mbox_snarf_sync_init;
+	MODULE_CONTEXT_SET(box, mbox_snarf_storage_module, mbox);
+	return box;
+}
+
+static void mbox_snarf_mail_storage_created(struct mail_storage *storage)
+{
+	struct mbox_snarf_mail_storage *mstorage;
+
+	if (mbox_snarf_next_hook_mail_storage_created != NULL)
+		mbox_snarf_next_hook_mail_storage_created(storage);
+
+	mstorage = p_new(storage->pool, struct mbox_snarf_mail_storage, 1);
+	mstorage->snarf_inbox_path =
+		p_strdup(storage->pool, home_expand(getenv("MBOX_SNARF")));
+	mstorage->module_ctx.super = storage->v;
+	storage->v.mailbox_open = mbox_snarf_mailbox_open;
+
+	MODULE_CONTEXT_SET(storage, mbox_snarf_storage_module, mstorage);
+}
+
+void mbox_snarf_plugin_init(void)
+{
+	const char *path;
+
+	path = getenv("MBOX_SNARF");
+	if (path != NULL) {
+		mbox_snarf_next_hook_mail_storage_created =
+			hook_mail_storage_created;
+		hook_mail_storage_created = mbox_snarf_mail_storage_created;
+	}
+}
+
+void mbox_snarf_plugin_deinit(void)
+{
+	if (getenv("MBOX_SNARF") != NULL) {
+		hook_mail_storage_created =
+			mbox_snarf_next_hook_mail_storage_created;
+	}
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/mbox-snarf/mbox-snarf-plugin.h	Thu May 17 20:25:26 2007 +0300
@@ -0,0 +1,7 @@
+#ifndef __MBOX_SNARF_PLUGIN_H
+#define __MBOX_SNARF_PLUGIN_H
+
+void mbox_snarf_plugin_init(void);
+void mbox_snarf_plugin_deinit(void);
+
+#endif