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