changeset 20392:596b61c6a86c

Added welcome plugin.
author Timo Sirainen <timo.sirainen@dovecot.fi>
date Mon, 20 Jun 2016 11:39:55 +0300
parents 76d36d9827e6
children 53ba3feb039a
files configure.ac src/plugins/Makefile.am src/plugins/welcome/Makefile.am src/plugins/welcome/welcome-plugin.c
diffstat 4 files changed, 162 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/configure.ac	Tue Jun 21 15:11:04 2016 +0300
+++ b/configure.ac	Mon Jun 20 11:39:55 2016 +0300
@@ -2954,6 +2954,7 @@
 src/plugins/imap-stats/Makefile
 src/plugins/trash/Makefile
 src/plugins/virtual/Makefile
+src/plugins/welcome/Makefile
 src/plugins/zlib/Makefile
 src/plugins/imap-zlib/Makefile
 stamp.h
--- a/src/plugins/Makefile.am	Tue Jun 21 15:11:04 2016 +0300
+++ b/src/plugins/Makefile.am	Mon Jun 20 11:39:55 2016 +0300
@@ -39,6 +39,7 @@
 	imap-stats \
 	trash \
 	virtual \
+	welcome \
 	$(ZLIB) \
 	$(FTS_LUCENE) \
 	$(FTS_SOLR) \
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/welcome/Makefile.am	Mon Jun 20 11:39:55 2016 +0300
@@ -0,0 +1,14 @@
+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
+
+NOPLUGIN_LDFLAGS =
+lib99_welcome_plugin_la_LDFLAGS = -module -avoid-version
+
+module_LTLIBRARIES = \
+	lib99_welcome_plugin.la
+
+lib99_welcome_plugin_la_SOURCES = \
+	welcome-plugin.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/plugins/welcome/welcome-plugin.c	Mon Jun 20 11:39:55 2016 +0300
@@ -0,0 +1,146 @@
+/* Copyright (c) 2015-2016 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "net.h"
+#include "str.h"
+#include "eacces-error.h"
+#include "write-full.h"
+#include "module-context.h"
+#include "mail-storage-private.h"
+
+#define WELCOME_SOCKET_TIMEOUT_SECS 30
+
+#define WELCOME_CONTEXT(obj) \
+	MODULE_CONTEXT(obj, welcome_storage_module)
+
+struct welcome_mailbox {
+	union mailbox_module_context module_ctx;
+	bool created;
+};
+
+static MODULE_CONTEXT_DEFINE_INIT(welcome_storage_module,
+				  &mail_storage_module_register);
+
+static void script_execute(struct mail_user *user, const char *cmd, bool wait)
+{
+	const char *socket_path, *const *args;
+	string_t *str;
+	char buf[1024];
+	int fd, ret;
+
+	if (user->mail_debug)
+		i_debug("welcome: Executing %s (wait=%d)", cmd, wait);
+
+	args = t_strsplit_spaces(cmd, " ");
+	socket_path = args[0];
+	args++;
+
+	if (*socket_path != '/') {
+		socket_path = t_strconcat(user->set->base_dir, "/",
+					  socket_path, NULL);
+	}
+	if ((fd = net_connect_unix_with_retries(socket_path, 1000)) < 0) {
+		if (errno == EACCES) {
+			i_error("welcome: %s",
+				eacces_error_get("net_connect_unix",
+						 socket_path));
+		} else {
+			i_error("welcome: net_connect_unix(%s) failed: %m",
+				socket_path);
+		}
+		return;
+	}
+
+	str = t_str_new(1024);
+	str_append(str, "VERSION\tscript\t3\t0\n");
+	if (!wait)
+		str_append(str, "noreply\n");
+	else
+		str_append(str, "-\n");
+	for (; *args != NULL; args++) {
+		str_append(str, *args);
+		str_append_c(str, '\n');
+	}
+	str_append_c(str, '\n');
+
+	alarm(WELCOME_SOCKET_TIMEOUT_SECS);
+	net_set_nonblock(fd, FALSE);
+	if (write_full(fd, str_data(str), str_len(str)) < 0)
+		i_error("write(%s) failed: %m", socket_path);
+	else if (wait) {
+		ret = read(fd, buf, sizeof(buf));
+		if (ret < 0)
+			i_error("welcome: read(%s) failed: %m", socket_path);
+		else if (ret < 2)
+			i_error("welcome: %s failed: Only %d bytes read", socket_path, ret);
+		else if (buf[0] != '+')
+			i_error("welcome: %s failed: Script returned error", socket_path);
+	}
+	if (close(fd) < 0)
+		i_error("close(%s) failed: %m", socket_path);
+}
+
+static int
+welcome_create_box(struct mailbox *box,
+		   const struct mailbox_update *update, bool directory)
+{
+	struct welcome_mailbox *wbox = WELCOME_CONTEXT(box);
+
+	if (wbox->module_ctx.super.create_box(box, update, directory) < 0)
+		return -1;
+	/* the mailbox isn't fully created here yet, so just mark it as created
+	   and wait until open() time to actually run it */
+	wbox->created = TRUE;
+	return 0;
+}
+
+static int welcome_open_box(struct mailbox *box)
+{
+	struct welcome_mailbox *wbox = WELCOME_CONTEXT(box);
+	const char *cmd;
+
+	cmd = !wbox->created ? NULL :
+		mail_user_plugin_getenv(box->storage->user, "welcome_script");
+	if (cmd != NULL) {
+		bool wait = mail_user_plugin_getenv(box->storage->user,
+						    "welcome_wait") != NULL;
+		script_execute(box->storage->user, cmd, wait);
+	}
+	return wbox->module_ctx.super.open(box);
+}
+
+static void welcome_mailbox_allocated(struct mailbox *box)
+{
+	struct mailbox_vfuncs *v = box->vlast;
+	struct welcome_mailbox *wbox;
+
+	if (!box->inbox_user)
+		return;
+
+	wbox = p_new(box->pool, struct welcome_mailbox, 1);
+	wbox->module_ctx.super = *v;
+	box->vlast = &wbox->module_ctx.super;
+
+	v->create_box = welcome_create_box;
+	v->open = welcome_open_box;
+	MODULE_CONTEXT_SET(box, welcome_storage_module, wbox);
+}
+
+static struct mail_storage_hooks welcome_mail_storage_hooks = {
+	.mailbox_allocated = welcome_mailbox_allocated
+};
+
+void welcome_plugin_init(struct module *module);
+void welcome_plugin_deinit(void);
+
+void welcome_plugin_init(struct module *module)
+{
+	mail_storage_hooks_add(module, &welcome_mail_storage_hooks);
+}
+
+void welcome_plugin_deinit(void)
+{
+	mail_storage_hooks_remove(&welcome_mail_storage_hooks);
+}
+
+const char *welcome_plugin_version = DOVECOT_ABI_VERSION;