dovecot-1.3: Initial implementation of LMTP server. Master proce...

dovecot at dovecot.org dovecot at dovecot.org
Fri Apr 17 01:12:36 EEST 2009


details:   http://hg.dovecot.org/dovecot-1.3/rev/a957a6be4af5
changeset: 9121:a957a6be4af5
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Apr 16 18:12:30 2009 -0400
description:
Initial implementation of LMTP server. Master process doesn't yet execute it though.

diffstat:

10 files changed, 999 insertions(+)
.hgignore            |    1 
configure.in         |    1 
src/Makefile.am      |    1 
src/lmtp/Makefile.am |   36 ++++
src/lmtp/client.c    |  271 +++++++++++++++++++++++++++++++++
src/lmtp/client.h    |   75 +++++++++
src/lmtp/commands.c  |  408 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/lmtp/commands.h  |   15 +
src/lmtp/main.c      |  182 ++++++++++++++++++++++
src/lmtp/main.h      |    9 +

diffs (truncated from 1057 to 300 lines):

diff -r 749339f9d1df -r a957a6be4af5 .hgignore
--- a/.hgignore	Thu Apr 16 18:11:00 2009 -0400
+++ b/.hgignore	Thu Apr 16 18:12:30 2009 -0400
@@ -65,6 +65,7 @@ src/lib-sql/sql-drivers-register.c
 src/lib-sql/sql-drivers-register.c
 src/lib-storage/register/mail-storage-register.c
 src/lib-storage/register/mailbox-list-register.c
+src/lmtp/lmtp
 src/master/dovecot
 src/master/ssl-build-param
 src/plugins/convert/convert-tool
diff -r 749339f9d1df -r a957a6be4af5 configure.in
--- a/configure.in	Thu Apr 16 18:11:00 2009 -0400
+++ b/configure.in	Thu Apr 16 18:12:30 2009 -0400
@@ -2406,6 +2406,7 @@ src/auth/Makefile
 src/auth/Makefile
 src/config/Makefile
 src/lda/Makefile
+src/lmtp/Makefile
 src/dict/Makefile
 src/imap/Makefile
 src/imap-login/Makefile
diff -r 749339f9d1df -r a957a6be4af5 src/Makefile.am
--- a/src/Makefile.am	Thu Apr 16 18:11:00 2009 -0400
+++ b/src/Makefile.am	Thu Apr 16 18:12:30 2009 -0400
@@ -26,6 +26,7 @@ SUBDIRS = \
 	pop3-login \
 	pop3 \
 	lda \
+	lmtp \
 	config \
 	tests \
 	util \
diff -r 749339f9d1df -r a957a6be4af5 src/lmtp/Makefile.am
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lmtp/Makefile.am	Thu Apr 16 18:12:30 2009 -0400
@@ -0,0 +1,36 @@
+pkglibexecdir = $(libexecdir)/dovecot
+
+pkglibexec_PROGRAMS = lmtp
+
+AM_CPPFLAGS = \
+	-I$(top_srcdir)/src/lib \
+	-I$(top_srcdir)/src/lib-settings \
+	-I$(top_srcdir)/src/lib-mail \
+	-I$(top_srcdir)/src/lib-imap \
+	-I$(top_srcdir)/src/lib-index \
+	-I$(top_srcdir)/src/lib-master \
+	-I$(top_srcdir)/src/lib-lda \
+	-I$(top_srcdir)/src/lib-storage \
+	-I$(top_srcdir)/src/lib-storage/index \
+	-I$(top_srcdir)/src/lib-storage/index/raw \
+	-DPKG_RUNDIR=\""$(rundir)"\"
+
+lmtp_LDFLAGS = -export-dynamic
+
+libs = \
+	../lib-lda/liblda.a \
+	$(LIBDOVECOT_STORAGE) \
+	$(LIBDOVECOT)
+
+lmtp_LDADD = $(libs) $(MODULE_LIBS)
+
+lmtp_DEPENDENCIES = $(libs)
+
+lmtp_SOURCES = \
+	main.c \
+	client.c \
+	commands.c
+
+noinst_HEADERS = \
+	client.h \
+	commands.h
diff -r 749339f9d1df -r a957a6be4af5 src/lmtp/client.c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/lmtp/client.c	Thu Apr 16 18:12:30 2009 -0400
@@ -0,0 +1,271 @@
+/* Copyright (c) 2009 Dovecot authors, see the included COPYING file */
+
+#include "lib.h"
+#include "buffer.h"
+#include "str.h"
+#include "llist.h"
+#include "istream.h"
+#include "ostream.h"
+#include "hostpid.h"
+#include "master-service-settings.h"
+#include "mail-namespace.h"
+#include "mail-storage.h"
+#include "main.h"
+#include "commands.h"
+#include "client.h"
+
+#include <unistd.h>
+
+#define CLIENT_IDLE_TIMEOUT_MSECS (1000*60)
+#define CLIENT_MAX_INPUT_SIZE 4096
+
+static struct client *clients = NULL;
+unsigned int clients_count = 0;
+
+static void client_idle_timeout(struct client *client)
+{
+	client_destroy(client,
+		       t_strdup_printf("421 4.4.2 %s", client->my_domain),
+		       "Disconnected for inactivity");
+}
+
+static int client_input_line(struct client *client, const char *line)
+{
+	const char *cmd, *args;
+
+	args = strchr(line, ' ');
+	if (args == NULL) {
+		cmd = line;
+		args = "";
+	} else {
+		cmd = t_strdup_until(line, args);
+		args++;
+	}
+	cmd = t_str_ucase(cmd);
+
+	if (strcmp(cmd, "LHLO") == 0)
+		return cmd_lhlo(client, args);
+	if (strcmp(cmd, "MAIL") == 0)
+		return cmd_mail(client, args);
+	if (strcmp(cmd, "RCPT") == 0)
+		return cmd_rcpt(client, args);
+	if (strcmp(cmd, "DATA") == 0)
+		return cmd_data(client, args);
+	if (strcmp(cmd, "QUIT") == 0)
+		return cmd_quit(client, args);
+	if (strcmp(cmd, "VRFY") == 0)
+		return cmd_vrfy(client, args);
+	if (strcmp(cmd, "RSET") == 0)
+		return cmd_rset(client, args);
+	if (strcmp(cmd, "NOOP") == 0)
+		return cmd_noop(client, args);
+
+	client_send_line(client, "502 5.5.2 Unknown command");
+	return 0;
+}
+
+int client_input_read(struct client *client)
+{
+	client->last_input = ioloop_time;
+	timeout_reset(client->to_idle);
+
+	switch (i_stream_read(client->input)) {
+	case -2:
+		/* buffer full */
+		client_destroy(client, "502 5.5.2",
+			       "Disconnected: Input buffer full");
+		return -1;
+	case -1:
+		/* disconnected */
+		client_destroy(client, NULL, NULL);
+		return -1;
+	case 0:
+		/* nothing new read */
+		return 0;
+	default:
+		/* something was read */
+		return 0;
+	}
+}
+
+void client_input_handle(struct client *client)
+{
+	struct ostream *output;
+	const char *line;
+	int ret;
+
+	output = client->output;
+	o_stream_ref(output);
+	o_stream_cork(output);
+	while ((line = i_stream_next_line(client->input)) != NULL) {
+		T_BEGIN {
+			ret = client_input_line(client, line);
+		} T_END;
+		if (ret < 0)
+			break;
+	}
+	o_stream_uncork(output);
+	o_stream_unref(&output);
+}
+
+void client_input(struct client *client)
+{
+	if (client_input_read(client) < 0)
+		return;
+	client_input_handle(client);
+}
+
+static void client_raw_user_create(struct client *client)
+{
+	struct mail_namespace *raw_ns;
+	struct mail_namespace_settings raw_ns_set;
+	const char *error;
+	void **sets;
+
+	sets = master_service_settings_get_others(service);
+
+	client->raw_mail_user = mail_user_alloc("raw user", sets[0]);
+	mail_user_set_home(client->raw_mail_user, "/");
+	if (mail_user_init(client->raw_mail_user, &error) < 0)
+		i_fatal("Raw user initialization failed: %s", error);
+
+	memset(&raw_ns_set, 0, sizeof(raw_ns_set));
+	raw_ns_set.location = "/tmp";
+
+	raw_ns = mail_namespaces_init_empty(client->raw_mail_user);
+	raw_ns->flags |= NAMESPACE_FLAG_INTERNAL;
+	raw_ns->set = &raw_ns_set;
+	if (mail_storage_create(raw_ns, "raw", 0, &error) < 0)
+		i_fatal("Couldn't create internal raw storage: %s", error);
+}
+
+struct client *client_create(int fd_in, int fd_out)
+{
+	struct client *client;
+
+	/* always use nonblocking I/O */
+	net_set_nonblock(fd_in, TRUE);
+	net_set_nonblock(fd_out, TRUE);
+
+	client = i_new(struct client, 1);
+	client->fd_in = fd_in;
+	client->fd_out = fd_out;
+	client->input = i_stream_create_fd(fd_in, CLIENT_MAX_INPUT_SIZE, FALSE);
+	client->output = o_stream_create_fd(fd_out, (size_t)-1, FALSE);
+
+	client->io = io_add(fd_in, IO_READ, client_input, client);
+        client->last_input = ioloop_time;
+	client->to_idle = timeout_add(CLIENT_IDLE_TIMEOUT_MSECS,
+				      client_idle_timeout, client);
+	client->my_domain = my_hostname;
+	client->state_pool = pool_alloconly_create("client state", 4096);
+	client->state.mail_data_fd = -1;
+
+	DLLIST_PREPEND(&clients, client);
+	clients_count++;
+
+	client_send_line(client, "220 %s Dovecot LMTP ready",
+			 client->my_domain);
+	client_raw_user_create(client);
+	return client;
+}
+
+void client_destroy(struct client *client, const char *prefix,
+		    const char *reason)
+{
+	client_disconnect(client, prefix, reason);
+
+	clients_count--;
+	DLLIST_REMOVE(&clients, client);
+
+	mail_user_unref(&client->raw_mail_user);
+	if (client->io != NULL)
+		io_remove(&client->io);
+	timeout_remove(&client->to_idle);
+	i_stream_destroy(&client->input);
+	o_stream_destroy(&client->output);
+
+	if (close(client->fd_in) < 0)
+		i_error("close(client in) failed: %m");
+	if (client->fd_in != client->fd_out) {
+		if (close(client->fd_out) < 0)
+			i_error("close(client out) failed: %m");
+	}
+	client_state_reset(client);
+	pool_unref(&client->state_pool);
+	i_free(client);
+
+	listener_client_destroyed();
+}
+
+static const char *client_get_disconnect_reason(struct client *client)
+{
+	errno = client->input->stream_errno != 0 ?
+		client->input->stream_errno :
+		client->output->stream_errno;
+	return errno == 0 || errno == EPIPE ? "Connection closed" :
+		t_strdup_printf("Connection closed: %m");
+}
+
+void client_disconnect(struct client *client, const char *prefix,
+		       const char *reason)
+{
+	if (client->disconnected)
+		return;
+
+	if (reason != NULL)
+		client_send_line(client, "%s %s", prefix, reason);
+	else
+		reason = client_get_disconnect_reason(client);
+	i_info("%s", reason);
+
+	client->disconnected = TRUE;
+}


More information about the dovecot-cvs mailing list