dovecot-2.2: lmtp: Added support for DSN ORCPT parameter.

dovecot at dovecot.org dovecot at dovecot.org
Thu Nov 13 02:00:10 UTC 2014


details:   http://hg.dovecot.org/dovecot-2.2/rev/3db5fbb216d3
changeset: 18074:3db5fbb216d3
user:      Timo Sirainen <tss at iki.fi>
date:      Thu Nov 13 03:58:51 2014 +0200
description:
lmtp: Added support for DSN ORCPT parameter.
If the parameter is specified, it's used as the original recipient address
in Sieve. The ORCPT parameter is also proxied to destination LMTP server if
used (without checking if it supports it). We don't currently advertise DSN
extension, so this feature won't be enabled automatically.

diffstat:

 src/lib-lda/lmtp-client.c |  39 +++++++++++++++++++++++++++-
 src/lib-lda/lmtp-client.h |   9 ++++++
 src/lmtp/client.h         |   3 ++
 src/lmtp/commands.c       |  64 +++++++++++++++++++++++++++++++++++++++++-----
 src/lmtp/lmtp-proxy.c     |   5 ++-
 src/lmtp/lmtp-proxy.h     |   1 +
 6 files changed, 109 insertions(+), 12 deletions(-)

diffs (284 lines):

diff -r 6c69fe41d553 -r 3db5fbb216d3 src/lib-lda/lmtp-client.c
--- a/src/lib-lda/lmtp-client.c	Thu Nov 13 02:48:22 2014 +0200
+++ b/src/lib-lda/lmtp-client.c	Thu Nov 13 03:58:51 2014 +0200
@@ -31,6 +31,8 @@
 	lmtp_callback_t *data_callback;
 	void *context;
 
+	struct lmtp_recipient_params params;
+
 	unsigned int data_called:1;
 	unsigned int failed:1;
 };
@@ -732,15 +734,35 @@
 	client->data_header = p_strdup(client->pool, str);
 }
 
+static void lmtp_append_xtext(string_t *dest, const char *str)
+{
+	unsigned int i;
+
+	for (i = 0; str[i] != '\0'; i++) {
+		if (str[i] >= 33 && str[i] <= 126 &&
+		    str[i] != '+' && str[i] != '=')
+			str_append_c(dest, str[i]);
+		else
+			str_printfa(dest, "+%02X", str[i]);
+	}
+}
+
 static void lmtp_client_send_rcpts(struct lmtp_client *client)
 {
 	const struct lmtp_rcpt *rcpt;
 	unsigned int i, count;
+	string_t *str = t_str_new(128);
 
 	rcpt = array_get(&client->recipients, &count);
 	for (i = client->rcpt_next_send_idx; i < count; i++) {
-		o_stream_nsend_str(client->output,
-			t_strdup_printf("RCPT TO:<%s>\r\n", rcpt[i].address));
+		str_truncate(str, 0);
+		str_printfa(str, "RCPT TO:<%s>", rcpt[i].address);
+		if (rcpt->params.dsn_orcpt != NULL) {
+			str_append(str, " ORCPT=");
+			lmtp_append_xtext(str, rcpt->params.dsn_orcpt);
+		}
+		str_append(str, "\r\n");
+		o_stream_nsend(client->output, str_data(str), str_len(str));
 	}
 	client->rcpt_next_send_idx = i;
 }
@@ -749,11 +771,24 @@
 			  lmtp_callback_t *rcpt_to_callback,
 			  lmtp_callback_t *data_callback, void *context)
 {
+	struct lmtp_recipient_params params;
+
+	memset(&params, 0, sizeof(params));
+	lmtp_client_add_rcpt_params(client, address, &params, rcpt_to_callback,
+				    data_callback, context);
+}
+
+void lmtp_client_add_rcpt_params(struct lmtp_client *client, const char *address,
+				 const struct lmtp_recipient_params *params,
+				 lmtp_callback_t *rcpt_to_callback,
+				 lmtp_callback_t *data_callback, void *context)
+{
 	struct lmtp_rcpt *rcpt;
 	enum lmtp_client_result result;
 
 	rcpt = array_append_space(&client->recipients);
 	rcpt->address = p_strdup(client->pool, address);
+	rcpt->params.dsn_orcpt = p_strdup(client->pool, params->dsn_orcpt);
 	rcpt->rcpt_to_callback = rcpt_to_callback;
 	rcpt->data_callback = data_callback;
 	rcpt->context = context;
diff -r 6c69fe41d553 -r 3db5fbb216d3 src/lib-lda/lmtp-client.h
--- a/src/lib-lda/lmtp-client.h	Thu Nov 13 02:48:22 2014 +0200
+++ b/src/lib-lda/lmtp-client.h	Thu Nov 13 03:58:51 2014 +0200
@@ -22,8 +22,13 @@
 	LMTP_CLIENT_RESULT_INTERNAL_ERROR = -1
 };
 
+struct lmtp_recipient_params {
+	const char *dsn_orcpt;
+};
+
 struct lmtp_client_settings {
 	const char *my_hostname;
+	/* The whole MAIL FROM line, including parameters */
 	const char *mail_from;
 	const char *dns_client_socket_path;
 
@@ -66,6 +71,10 @@
 void lmtp_client_add_rcpt(struct lmtp_client *client, const char *address,
 			  lmtp_callback_t *rcpt_to_callback,
 			  lmtp_callback_t *data_callback, void *context);
+void lmtp_client_add_rcpt_params(struct lmtp_client *client, const char *address,
+				 const struct lmtp_recipient_params *params,
+				 lmtp_callback_t *rcpt_to_callback,
+				 lmtp_callback_t *data_callback, void *context);
 /* Start sending input stream as DATA. */
 void lmtp_client_send(struct lmtp_client *client, struct istream *data_input);
 /* Call this function whenever input stream can potentially be read forward.
diff -r 6c69fe41d553 -r 3db5fbb216d3 src/lmtp/client.h
--- a/src/lmtp/client.h	Thu Nov 13 02:48:22 2014 +0200
+++ b/src/lmtp/client.h	Thu Nov 13 03:58:51 2014 +0200
@@ -2,12 +2,15 @@
 #define CLIENT_H
 
 #include "net.h"
+#include "lmtp-client.h"
 
 #define CLIENT_MAIL_DATA_MAX_INMEMORY_SIZE (1024*128)
 
 struct mail_recipient {
 	const char *address;
 	const char *detail; /* +detail part is also in address */
+	struct lmtp_recipient_params params;
+
 	struct mail_storage_service_user *service_user;
 };
 
diff -r 6c69fe41d553 -r 3db5fbb216d3 src/lmtp/commands.c
--- a/src/lmtp/commands.c	Thu Nov 13 02:48:22 2014 +0200
+++ b/src/lmtp/commands.c	Thu Nov 13 03:58:51 2014 +0200
@@ -11,6 +11,7 @@
 #include "ostream.h"
 #include "istream-dot.h"
 #include "safe-mkstemp.h"
+#include "hex-dec.h"
 #include "var-expand.h"
 #include "restrict-access.h"
 #include "settings-parser.h"
@@ -149,6 +150,33 @@
 	return 0;
 }
 
+static const char *
+parse_xtext(struct client *client, const char *value)
+{
+	const char *p;
+	string_t *str;
+	unsigned int i;
+
+	p = strchr(value, '+');
+	if (p == NULL)
+		return p_strdup(client->state_pool, value);
+
+	/*
+	   hexchar = ASCII "+" immediately followed by two upper case
+		     hexadecimal digits
+	*/
+	str = t_str_new(128);
+	for (i = 0; value[i] != '\0'; i++) {
+		if (value[i] == '+' && value[i+1] != '\0' && value[i+2] != '\0') {
+			str_append_c(str, hex2dec((const void *)(value+i+1), 2));
+			i += 2;
+		} else {
+			str_append_c(str, value[i]);
+		}
+	}
+	return p_strdup(client->state_pool, str_c(str));
+}
+
 int cmd_mail(struct client *client, const char *args)
 {
 	const char *addr, *const *argv;
@@ -269,7 +297,8 @@
 }
 
 static bool client_proxy_rcpt(struct client *client, const char *address,
-			      const char *username, const char *detail)
+			      const char *username, const char *detail,
+			      const struct lmtp_recipient_params *params)
 {
 	struct auth_master_connection *auth_conn;
 	struct lmtp_proxy_rcpt_settings set;
@@ -311,6 +340,7 @@
 	set.port = client->local_port;
 	set.protocol = LMTP_CLIENT_PROTOCOL_LMTP;
 	set.timeout_msecs = LMTP_PROXY_DEFAULT_TIMEOUT_MSECS;
+	set.params = *params;
 
 	if (!client_proxy_rcpt_parse_fields(&set, fields, &username)) {
 		/* not proxying this user */
@@ -537,7 +567,8 @@
 {
 	struct mail_recipient rcpt;
 	struct mail_storage_service_input input;
-	const char *address, *username, *detail, *prefix;
+	const char *params, *address, *username, *detail, *prefix;
+	const char *const *argv;
 	const char *error = NULL;
 	int ret = 0;
 
@@ -547,7 +578,7 @@
 	}
 
 	if (strncasecmp(args, "TO:", 3) != 0 ||
-	    parse_address(args + 3, &address, &args) < 0) {
+	    parse_address(args + 3, &address, &params) < 0) {
 		client_send_line(client, "501 5.5.4 Invalid parameters");
 		return 0;
 	}
@@ -555,16 +586,22 @@
 	memset(&rcpt, 0, sizeof(rcpt));
 	address = lmtp_unescape_address(address);
 
-	if (*args != '\0') {
-		client_send_line(client, "501 5.5.4 Unsupported options");
-		return 0;
+	argv = t_strsplit(params, " ");
+	for (; *argv != NULL; argv++) {
+		if (strncasecmp(*argv, "ORCPT=", 6) == 0) {
+			rcpt.params.dsn_orcpt = parse_xtext(client, *argv + 6);
+		} else {
+			client_send_line(client, "501 5.5.4 Unsupported options");
+			return 0;
+		}
 	}
 	rcpt_address_parse(client, address, &username, &detail);
 
 	client_state_set(client, "RCPT TO", address);
 
 	if (client->lmtp_set->lmtp_proxy) {
-		if (client_proxy_rcpt(client, address, username, detail))
+		if (client_proxy_rcpt(client, address, username, detail,
+				      &rcpt.params))
 			return 0;
 	}
 
@@ -647,6 +684,15 @@
 	return 0;
 }
 
+static bool orcpt_get_valid_rfc822(const char *orcpt, const char **addr_r)
+{
+	if (orcpt == NULL || strncasecmp(orcpt, "rfc822;", 7) != 0)
+		return FALSE;
+	/* FIXME: we should verify the address further */
+	*addr_r = orcpt + 7;
+	return TRUE;
+}
+
 static int
 client_deliver(struct client *client, const struct mail_recipient *rcpt,
 	       struct mail *src_mail, struct mail_deliver_session *session)
@@ -709,7 +755,9 @@
 	dctx.src_mail = src_mail;
 	dctx.src_envelope_sender = client->state.mail_from;
 	dctx.dest_user = client->state.dest_user;
-	if (*dctx.set->lda_original_recipient_header != '\0') {
+	if (orcpt_get_valid_rfc822(rcpt->params.dsn_orcpt, &dctx.dest_addr)) {
+		/* used ORCPT */
+	} else if (*dctx.set->lda_original_recipient_header != '\0') {
 		dctx.dest_addr = mail_deliver_get_address(src_mail,
 				dctx.set->lda_original_recipient_header);
 	}
diff -r 6c69fe41d553 -r 3db5fbb216d3 src/lmtp/lmtp-proxy.c
--- a/src/lmtp/lmtp-proxy.c	Thu Nov 13 02:48:22 2014 +0200
+++ b/src/lmtp/lmtp-proxy.c	Thu Nov 13 03:58:51 2014 +0200
@@ -288,8 +288,9 @@
 	rcpt->address = p_strdup(proxy->pool, address);
 	array_append(&proxy->rcpt_to, &rcpt, 1);
 
-	lmtp_client_add_rcpt(conn->client, address, lmtp_proxy_conn_rcpt_to,
-			     lmtp_proxy_conn_data, rcpt);
+	lmtp_client_add_rcpt_params(conn->client, address, &set->params,
+				    lmtp_proxy_conn_rcpt_to,
+				    lmtp_proxy_conn_data, rcpt);
 	return 0;
 }
 
diff -r 6c69fe41d553 -r 3db5fbb216d3 src/lmtp/lmtp-proxy.h
--- a/src/lmtp/lmtp-proxy.h	Thu Nov 13 02:48:22 2014 +0200
+++ b/src/lmtp/lmtp-proxy.h	Thu Nov 13 03:58:51 2014 +0200
@@ -22,6 +22,7 @@
 	unsigned int port;
 	unsigned int timeout_msecs;
 	enum lmtp_client_protocol protocol;
+	struct lmtp_recipient_params params;
 };
 
 typedef void lmtp_proxy_finish_callback_t(void *context);


More information about the dovecot-cvs mailing list