summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'mail-mta/exim/files/exim_482_dsn_1_3.patch')
-rw-r--r--mail-mta/exim/files/exim_482_dsn_1_3.patch1212
1 files changed, 1212 insertions, 0 deletions
diff --git a/mail-mta/exim/files/exim_482_dsn_1_3.patch b/mail-mta/exim/files/exim_482_dsn_1_3.patch
new file mode 100644
index 000000000000..c30069967309
--- /dev/null
+++ b/mail-mta/exim/files/exim_482_dsn_1_3.patch
@@ -0,0 +1,1212 @@
+Modified for 4.82 by Gentoo -- not the official patch from
+http://sourceforge.net/projects/eximdsn/
+
+diff -Naur exim-4.82_RC5.orig/README.DSN exim-4.82_RC5/README.DSN
+--- exim-4.82_RC5.orig/README.DSN 1970-01-01 01:00:00.000000000 +0100
++++ exim-4.82_RC5/README.DSN 2013-10-27 21:47:32.000000000 +0100
+@@ -0,0 +1,118 @@
++Exim DSN Patch (4.76)
++---------------------
++
++This patch is free software; you can redistribute it and/or modify
++it under the terms of the GNU General Public License as published by
++the Free Software Foundation; either version 2 of the License, or
++(at your option) any later version.
++
++This patch is distributed in the hope that it will be useful,
++but WITHOUT ANY WARRANTY; without even the implied warranty of
++MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
++GNU General Public License for more details.
++
++You should have received a copy of the GNU General Public License
++along with this patch; if not, write to the Free Software
++Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
++
++Install
++-------
++cd into the source tree for a vanilla exim
++
++patch -p1 </path/to/patch/file.patch
++
++Example :-
++[root@linuxbuild exim-4.72-test]# patch -p1 <../exim.dsn.patch-472
++
++Expected Output :-
++patching file README.DSN
++patching file src/config.h.defaults
++patching file src/deliver.c
++patching file src/exim.c
++patching file src/exim.h
++patching file src/globals.c
++patching file src/globals.h
++patching file src/local_scan.h
++patching file src/macros.h
++patching file src/readconf.c
++patching file src/route.c
++patching file src/smtp_in.c
++patching file src/spool_in.c
++patching file src/spool_out.c
++patching file src/structs.h
++patching file src/transport.c
++patching file src/transports/smtp.c
++
++
++This patch can be included / excluded from the compilation by use of the #define SUPPORT_DSN
++which gets added into src/config.h.defaults & src/EDITME by the patch.
++
++Use
++---
++
++The facility (once compiled in) can be turned on for a particular router via the
++dsn_process directive Eg :-
++
++dest_delivery_int:
++ driver = manualroute
++ domains = +relay_to_domains
++ condition = ${if eq {${lc:$sender_address_domain}}\
++ {domain.com}\
++ {yes}{no}\
++ }
++ dsn_process
++ hide route_data = ${lc:${extract{mailHost}{$address_data}{$value}{}}}
++ transport = remote_smtp
++
++Exim will produce 1 of 2 DSN's back to the originator, or pass on the DSN request.
++The 2 DSN's will either contain (relayed via non "Remote SMTP" router) or
++(relayed to non-DSN-aware mailer) depending on if the delivery was VIA an SMTP
++transport or not.
++
++
++Credits
++-------
++
++The original work for the patch was done by Philip Hazel in Exim 3
++
++The extract was taken and re-applied to Exim 4 by the following :-
++Phil Bingham (phil.bingham@cwipapps.net)
++Steve Falla (steve.falla@cwipapps.net)
++Ray Edah (ray.edah@cwipapps.net)
++Andrew Johnson (andrew.johnson@cwippaps.net)
++Adrian Hungate (adrian.hungate@cwipapps.net)
++
++Now Primarily maintained by :-
++Andrew Johnson (andrew.johnson@cwippaps.net)
++
++Contributions
++-------------
++Andrey J. Melnikoff (TEMHOTA) (temnota@kmv.ru)
++
++
++ChangeLog
++---------
++
++14-Apr-2006 : Changed subject to "Delivery Status Notification"
++
++17-May-2006 : debug_printf in spool-in.c were not wrapped with #ifndef COMPILE_UTILITY
++ thanks to Andrey J. Melnikoff for this information
++
++12-Sep-2006 : Now supports Exim 4.63
++
++12-Sep-2006 : src/EDITME did not include the #define SUPPORT_DSN as stated
++ in the documentation, this has now been corrected
++ thanks to Robert Kehl for this information
++
++28-Jul-2008 : New version for exim 4.69 released.
++
++02-Jul-2010 : New version for exim 4.72 released.
++
++20-May-2011 : New version for exim 4.76 released.
++
++
++Support for this patch (limited though it is) will only be provided through the SourceForge
++project page (http://sourceforge.net/projects/eximdsn/)
++
++--
++Andrew Johnson Cable & Wireless
+diff -Naur exim-4.82_RC5.orig/src/config.h.defaults exim-4.82_RC5/src/config.h.defaults
+--- exim-4.82_RC5.orig/src/config.h.defaults 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/config.h.defaults 2013-10-27 21:47:32.000000000 +0100
+@@ -136,6 +136,7 @@
+ #define SUPPORT_MOVE_FROZEN_MESSAGES
+ #define SUPPORT_PAM
+ #define SUPPORT_TLS
++#define SUPPORT_DSN
+ #define SUPPORT_TRANSLATE_IP_ADDRESS
+
+ #define SYSLOG_LOG_PID
+diff -Naur exim-4.82_RC5.orig/src/deliver.c exim-4.82_RC5/src/deliver.c
+--- exim-4.82_RC5.orig/src/deliver.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/deliver.c 2013-10-27 21:47:32.000000000 +0100
+@@ -63,6 +63,9 @@
+ static address_item *addr_remote = NULL;
+ static address_item *addr_route = NULL;
+ static address_item *addr_succeed = NULL;
++#ifdef SUPPORT_DSN
++static address_item *addr_dsntmp = NULL;
++#endif
+
+ static FILE *message_log = NULL;
+ static BOOL update_spool;
+@@ -2966,6 +2969,15 @@
+ addr->flags |= af_prdr_used; break;
+ #endif
+
++ #ifdef SUPPORT_DSN
++ case 'D':
++ if (addr == NULL) break;
++ addr->dsn_aware = (*ptr)? string_copy(ptr) : string_copy(" ");
++ while (*ptr++);
++ DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %s\n", addr->dsn_aware);
++ break;
++ #endif
++
+ case 'A':
+ if (addr == NULL)
+ {
+@@ -4074,6 +4086,15 @@
+ if (addr->flags & af_prdr_used) rmt_dlv_checked_write(fd, "P", 1);
+ #endif
+
++ #ifdef SUPPORT_DSN
++ if (addr->dsn_aware == NULL)
++ addr->dsn_aware = string_copy(" ");
++ DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %s\n", addr->dsn_aware);
++ sprintf(big_buffer, "D%s", addr->dsn_aware);
++ DEBUG(D_deliver) debug_printf("DSN write: big_buffer = %s (%d)\n", big_buffer, strlen(big_buffer)+1);
++ write(fd, big_buffer, strlen(big_buffer)+1);
++ #endif
++
+ /* Retry information: for most success cases this will be null. */
+
+ for (r = addr->retries; r != NULL; r = r->next)
+@@ -5219,6 +5240,14 @@
+ if (r->pno >= 0)
+ new->onetime_parent = recipients_list[r->pno].address;
+
++ #ifdef SUPPORT_DSN
++ /* If DSN support is enabled, set the dsn flags and the original receipt
++ to be passed on to other DSN enabled MTAs */
++ new->dsn_flags = r->dsn_flags & rf_dsnflags;
++ new->dsn_orcpt = r->orcpt;
++ debug_printf("DSN (deliver): orcpt: %s flags: %d\n", new->dsn_orcpt, new->dsn_flags);
++ #endif
++
+ switch (process_recipients)
+ {
+ /* RECIP_DEFER is set when a system filter freezes a message. */
+@@ -6163,6 +6192,12 @@
+ regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
+ #endif
+
++ #ifdef SUPPORT_DSN
++ /* Set the regex to check for DSN support on remote MTA */
++ if (regex_DSN == NULL) regex_DSN =
++ regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
++ #endif
++
+ /* Now sort the addresses if required, and do the deliveries. The yield of
+ do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
+ cannot be delivered in one transaction. */
+@@ -6267,6 +6302,179 @@
+
+ else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed);
+
++#ifdef SUPPORT_DSN
++/* ********** philb - Send DSN for successful messages */
++
++addr_dsntmp = addr_succeed;
++
++while(addr_dsntmp != NULL)
++{
++ BOOL dsn_sendmessage = FALSE;
++ uschar dsnmsgbuf[4096];
++
++ DEBUG(D_deliver)
++ debug_printf("DSN: processing router : %s\n", addr_dsntmp->router->name);
++
++ DEBUG(D_deliver)
++ debug_printf("DSN: processing successful delivery address: %s\n", addr_dsntmp->address);
++
++ if (testflag(addr_dsntmp, af_ignore_error))
++ {
++ DEBUG(D_deliver)
++ debug_printf("DSN: Ignore error for: %s\n", addr_dsntmp->address);
++ }
++ else
++ {
++ DEBUG(D_deliver) debug_printf("DSN: Checking Flag\n");
++ if (addr_dsntmp->dsn_aware == NULL) {
++ DEBUG(D_deliver) debug_printf("DSN: dsn_aware was NULL, setting to space at %s %d\n", __FILE__, __LINE__);
++ addr_dsntmp->dsn_aware = string_copy(" ");
++ }
++ DEBUG(D_deliver) debug_printf("DSN: Sender_address: %s\n", sender_address);
++ DEBUG(D_deliver) debug_printf("DSN: orcpt: %s flags: %d\n", addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags);
++ DEBUG(D_deliver) debug_printf("DSN: envid: %s ret: %d\n", dsn_envid, dsn_ret);
++ DEBUG(D_deliver) debug_printf("DSN: Remote SMTP server supports DSN: %s\n", addr_dsntmp->dsn_aware);
++
++ /* Process the flags */
++ if((addr_dsntmp->dsn_flags & rf_dsnflags) != 0)
++ {
++ /* We've got at least one flag set */
++
++ /* set flag so we don't send bounces */
++ setflag(addr_dsntmp, af_ignore_error);
++
++ if((addr_dsntmp->dsn_flags & rf_notify_never) != 0)
++ {
++ DEBUG(D_deliver) debug_printf("DSN: NEVER FLAG\n");
++
++ /* nothing to do here */
++ }
++
++ if((addr_dsntmp->dsn_flags & rf_notify_success) != 0)
++ {
++ DEBUG(D_deliver) debug_printf("DSN: SUCCESS FLAG\n");
++
++ dsn_sendmessage = TRUE;
++ }
++
++ if((addr_dsntmp->dsn_flags & rf_notify_failure) != 0)
++ {
++ DEBUG(D_deliver) debug_printf("DSN: FAILURE FLAG\n");
++
++ /* allow bounce messages */
++ clearflag(addr_dsntmp, af_ignore_error);
++ }
++
++ if((addr_dsntmp->dsn_flags & rf_notify_delay) != 0)
++ {
++ DEBUG(D_deliver) debug_printf("DSN: DELAY FLAG\n");
++
++ /* hmm, what to do here? */
++ }
++ }
++
++ if ((addr_dsntmp->dsn_aware != 0) && (addr_dsntmp->dsn_aware[0] != 'Y') && (dsn_sendmessage == TRUE) && (addr_dsntmp->router->dsn_process == TRUE))
++ {
++ pid_t pid;
++ int fd;
++
++ /* remote MTA does not support DSN, so we need to send message */
++
++ /* create exim process to send message */
++ pid = child_open_exim(&fd);
++
++ DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %d\n", pid);
++
++ if (pid < 0) /* Creation of child failed */
++ {
++ log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to "
++ "create child process to send failure message: %s", getpid(),
++ getppid(), strerror(errno));
++
++ DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n");
++
++ }
++ else /* Creation of child succeeded */
++ {
++ FILE *f = fdopen(fd, "wb");
++ int topt = topt_add_return_path;
++ uschar boundaryStr[64];
++
++ DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address);
++
++ /* build unique id for MIME boundary */
++ snprintf(boundaryStr, 63, "%d-cwdsn-%d", pid, rand());
++ DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr);
++
++ /* if the sender doesn't want the whole message returned, don't send the body */
++ if (dsn_ret != dsn_ret_full) topt |= topt_no_body;
++
++ if (errors_reply_to != NULL) fprintf(f,"Reply-To: %s\n", errors_reply_to);
++
++ fprintf(f,"Auto-Submitted: auto-generated\n");
++ fprintf(f,"From: Mail Delivery System <Mailer-Daemon@%s>\n", qualify_domain_sender);
++ fprintf(f,"To: %s\n", sender_address);
++ fprintf(f,"Subject: Delivery Status Notification\n");
++ fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr);
++ fprintf(f,"MIME-Version: 1.0\n\n");
++
++ fprintf(f,"--%s\n", boundaryStr);
++ fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n");
++
++ fprintf(f,"This message was created automatically by mail delivery software.\n");
++ fprintf(f," ----- The following addresses had successful delivery notifications -----\n");
++/* AH: added specific message for non "Remote SMTP" situations */
++ if (addr_dsntmp->dsn_aware[0] == 'N') {
++ fprintf(f,"<%s> (relayed to non-DSN-aware mailer)\n\n", addr_dsntmp->address);
++ } else {
++ fprintf(f,"<%s> (relayed via non \"Remote SMTP\" router)\n\n", addr_dsntmp->address);
++ }
++
++ fprintf(f,"--%s\n", boundaryStr);
++ fprintf(f,"Content-type: message/delivery-status\n\n");
++
++ if (dsn_envid) { /* Test for NULL added by GC */
++ fprintf(f,"Original-Envelope-Id: %s\n", dsn_envid);
++ }
++ fprintf(f,"Reporting-MTA: dns; %s\n", qualify_domain_sender);
++ if (addr_dsntmp->dsn_orcpt) { /* Test for NULL added by GC */
++ fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt);
++ }
++ fprintf(f,"Action: delivered\n\n");
++
++ fprintf(f,"--%s\n", boundaryStr);
++ fprintf(f,"Content-type: message/rfc822\n\n");
++
++ fflush(f);
++ transport_filter_argv = NULL; /* Just in case */
++ return_path = sender_address; /* In case not previously set */
++
++ /* Write the original email out */
++ transport_write_message(NULL, fileno(f), topt, 2048, NULL, NULL, NULL, NULL, NULL, 0);
++ fflush(f);
++
++ fprintf(f,"\n");
++ fprintf(f,"--%s--\n", boundaryStr);
++
++ fflush(f);
++ fclose(f);
++ rc = child_close(pid, 0); /* Waits for child to close, no timeout */
++ }
++ }
++ else
++ { if (addr_dsntmp->router->dsn_process == TRUE)
++ DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message ***\n");
++ if (addr_dsntmp->router->dsn_process == FALSE)
++ DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message (gagged) ***\n");
++ }
++ }
++
++ addr_dsntmp = addr_dsntmp->next;
++}
++
++/* ********** philb - end of mod */
++#endif
++
+ /* If any addresses failed, we must send a message to somebody, unless
+ af_ignore_error is set, in which case no action is taken. It is possible for
+ several messages to get sent if there are addresses with different
+diff -Naur exim-4.82_RC5.orig/src/EDITME exim-4.82_RC5/src/EDITME
+--- exim-4.82_RC5.orig/src/EDITME 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/EDITME 2013-10-27 21:47:32.000000000 +0100
+@@ -192,6 +192,8 @@
+ # least one type of lookup. You should consider whether you want to build
+ # the Exim monitor or not.
+
++# Support DSN
++SUPPORT_DSN=yes
+
+ #------------------------------------------------------------------------------
+ # These settings determine which individual router drivers are included in the
+diff -Naur exim-4.82_RC5.orig/src/exim.c exim-4.82_RC5/src/exim.c
+--- exim-4.82_RC5.orig/src/exim.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/exim.c 2013-10-27 21:47:32.000000000 +0100
+@@ -831,6 +831,9 @@
+ #ifdef EXPERIMENTAL_REDIS
+ fprintf(f, " Experimental_Redis");
+ #endif
++#ifdef SUPPORT_DSN
++ fprintf(f, " C&W_DSN_1.3");
++#endif
+ fprintf(f, "\n");
+
+ fprintf(f, "Lookups (built-in):");
+@@ -2653,6 +2656,16 @@
+ break;
+ }
+
++ #ifdef SUPPORT_DSN
++ /* -MCD: set the smtp_use_dsn flag; this indicates that the host
++ that exim is connected to supports the esmtp extension DSN */
++ else if (strcmp(argrest, "CD") == 0)
++ {
++ smtp_use_dsn = TRUE;
++ break;
++ }
++ #endif
++
+ /* -MCP: set the smtp_use_pipelining flag; this is useful only when
+ it preceded -MC (see above) */
+
+diff -Naur exim-4.82_RC5.orig/src/globals.c exim-4.82_RC5/src/globals.c
+--- exim-4.82_RC5.orig/src/globals.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/globals.c 2013-10-27 21:47:32.000000000 +0100
+@@ -124,6 +124,13 @@
+ uschar *local_scan_path = NULL;
+ #endif
+
++#ifdef SUPPORT_DSN
++BOOL dsn = TRUE;
++uschar *dsn_envid = NULL;
++int dsn_ret = 0;
++const pcre *regex_DSN = NULL;
++BOOL smtp_use_dsn = FALSE;
++#endif
+
+ #ifdef SUPPORT_TLS
+ BOOL gnutls_compat_mode = FALSE;
+@@ -341,6 +348,11 @@
+ NULL, /* authenticator */
+ NULL, /* auth_id */
+ NULL, /* auth_sndr */
++ #ifdef SUPPORT_DSN
++ NULL, /* dsn_orcpt */
++ 0, /* dsn_flags */
++ NULL, /* dsn_aware */
++ #endif
+ (uid_t)(-1), /* uid */
+ (gid_t)(-1), /* gid */
+ 0, /* flags */
+@@ -1096,6 +1108,9 @@
+ TRUE, /* verify_sender */
+ FALSE, /* uid_set */
+ FALSE, /* unseen */
++#ifdef SUPPORT_DSN
++ FALSE, /* dsn_process */
++#endif
+
+ self_freeze, /* self_code */
+ (uid_t)(-1), /* uid */
+@@ -1105,6 +1120,7 @@
+ NULL, /* transport instance */
+ NULL, /* pass_router */
+ NULL /* redirect_router */
++
+ };
+
+ uschar *router_name = NULL;
+diff -Naur exim-4.82_RC5.orig/src/globals.h exim-4.82_RC5/src/globals.h
+--- exim-4.82_RC5.orig/src/globals.h 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/globals.h 2013-10-27 21:47:32.000000000 +0100
+@@ -130,6 +130,13 @@
+ extern int (*receive_ferror)(void);
+ extern BOOL (*receive_smtp_buffered)(void);
+
++#ifdef SUPPORT_DSN
++extern BOOL dsn; /* FALSE if DSN not to be used */
++extern uschar *dsn_envid; /* DSN envid string */
++extern int dsn_ret; /* DSN ret type*/
++extern const pcre *regex_DSN; /* For recognizing DSN settings */
++extern BOOL smtp_use_dsn; /* Global for passed connections */
++#endif
+
+ /* For clearing, saving, restoring address expansion variables. We have to have
+ the size of this vector set explicitly, because it is referenced from more than
+diff -Naur exim-4.82_RC5.orig/src/local_scan.h exim-4.82_RC5/src/local_scan.h
+--- exim-4.82_RC5.orig/src/local_scan.h 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/local_scan.h 2013-10-27 21:47:32.000000000 +0100
+@@ -124,9 +124,13 @@
+ field is always NULL except for one_time aliases that had errors_to on the
+ routers that generated them. */
+
++/* Added the dsn attributes orcpt and dsn_flags for DSN support*/
++
+ typedef struct recipient_item {
+ uschar *address; /* the recipient address */
+ int pno; /* parent number for "one_time" alias, or -1 */
++ uschar *orcpt; /* DSN orcpt */
++ int dsn_flags; /* DSN flags */
+ uschar *errors_to; /* the errors_to address or NULL */
+ #ifdef EXPERIMENTAL_BRIGHTMAIL
+ uschar *bmi_optin;
+diff -Naur exim-4.82_RC5.orig/src/macros.h exim-4.82_RC5/src/macros.h
+--- exim-4.82_RC5.orig/src/macros.h 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/macros.h 2013-10-27 21:47:32.000000000 +0100
+@@ -778,6 +778,22 @@
+ #define topt_no_body 0x040 /* Omit body */
+ #define topt_escape_headers 0x080 /* Apply escape check to headers */
+
++ /* Flags for recipient_block, used in DSN support */
++
++ #define rf_onetime 0x01 /* A one-time alias */
++ #define rf_notify_never 0x02 /* NOTIFY= settings */
++ #define rf_notify_success 0x04
++ #define rf_notify_failure 0x08
++ #define rf_notify_delay 0x10
++
++ #define rf_dsnflags (rf_notify_never | rf_notify_success | \
++ rf_notify_failure | rf_notify_delay)
++
++ /* DSN RET types */
++
++ #define dsn_ret_full 1
++ #define dsn_ret_hdrs 2
++
+ /* Codes for the host_find_failed and host_all_ignored options. */
+
+ #define hff_freeze 0
+diff -Naur exim-4.82_RC5.orig/src/readconf.c exim-4.82_RC5/src/readconf.c
+--- exim-4.82_RC5.orig/src/readconf.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/readconf.c 2013-10-27 21:49:15.000000000 +0100
+@@ -229,6 +229,9 @@
+ /* This option is now a no-op, retained for compability */
+ { "drop_cr", opt_bool, &drop_cr },
+ /*********************************************************/
++#ifdef SUPPORT_DSN
++ { "dsn", opt_bool, &dsn },
++#endif
+ { "dsn_from", opt_stringptr, &dsn_from },
+ { "envelope_to_remove", opt_bool, &envelope_to_remove },
+ { "errors_copy", opt_stringptr, &errors_copy },
+diff -Naur exim-4.82_RC5.orig/src/receive.c exim-4.82_RC5/src/receive.c
+--- exim-4.82_RC5.orig/src/receive.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/receive.c 2013-10-27 21:47:32.000000000 +0100
+@@ -490,6 +490,8 @@
+ memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
+ }
+
++/* memset added by GC to blank dsn records, etc. */
++memset(&recipients_list[recipients_count], 0, sizeof(recipient_item));
+ recipients_list[recipients_count].address = recipient;
+ recipients_list[recipients_count].pno = pno;
+ #ifdef EXPERIMENTAL_BRIGHTMAIL
+diff -Naur exim-4.82_RC5.orig/src/route.c exim-4.82_RC5/src/route.c
+--- exim-4.82_RC5.orig/src/route.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/route.c 2013-10-27 21:47:32.000000000 +0100
+@@ -58,6 +58,10 @@
+ (void *)offsetof(router_instance, domains) },
+ { "driver", opt_stringptr|opt_public,
+ (void *)offsetof(router_instance, driver_name) },
++ #ifdef SUPPORT_DSN
++ { "dsn_process", opt_bool|opt_public,
++ (void *)offsetof(router_instance, dsn_process) },
++ #endif
+ { "errors_to", opt_stringptr|opt_public,
+ (void *)(offsetof(router_instance, errors_to)) },
+ { "expn", opt_bool|opt_public,
+@@ -270,6 +274,13 @@
+
+ if (r->pass_router_name != NULL)
+ set_router(r, r->pass_router_name, &(r->pass_router), TRUE);
++
++ #ifdef SUPPORT_DSN
++ if (r->dsn_process == FALSE)
++ DEBUG(D_route) debug_printf("%s router skipping DSN - add dsn_process to router\n", r->name);
++ if (r->dsn_process == TRUE)
++ DEBUG(D_route) debug_printf("%s router performing DSN \n", r->name);
++ #endif
+ }
+ }
+
+@@ -1412,7 +1423,10 @@
+
+ copyflag(new, addr, af_propagate);
+ new->p.address_data = addr->p.address_data;
+-
++#ifdef SUPPORT_DSN
++ new->dsn_flags = addr->dsn_flags;
++ new->dsn_orcpt = addr->dsn_orcpt;
++#endif
+
+ /* As it has turned out, we haven't set headers_add or headers_remove for the
+ * clone. Thinking about it, it isn't entirely clear whether they should be
+diff -Naur exim-4.82_RC5.orig/src/smtp_in.c exim-4.82_RC5/src/smtp_in.c
+--- exim-4.82_RC5.orig/src/smtp_in.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/smtp_in.c 2013-10-27 21:47:32.000000000 +0100
+@@ -213,6 +213,9 @@
+ #ifdef EXPERIMENTAL_PRDR
+ ENV_MAIL_OPT_PRDR,
+ #endif
++#ifdef SUPPORT_DSN
++ ENV_MAIL_OPT_RET, ENV_MAIL_OPT_ENVID,
++#endif
+ ENV_MAIL_OPT_NULL
+ };
+ typedef struct {
+@@ -228,6 +231,10 @@
+ #ifdef EXPERIMENTAL_PRDR
+ { US"PRDR", ENV_MAIL_OPT_PRDR, FALSE },
+ #endif
++#ifdef SUPPORT_DSN
++ { US"RET", ENV_MAIL_OPT_RET, FALSE },
++ { US"ENVID", ENV_MAIL_OPT_ENVID, FALSE },
++#endif
+ { US"NULL", ENV_MAIL_OPT_NULL, FALSE }
+ };
+
+@@ -1073,6 +1080,13 @@
+ sender_verified_list = NULL; /* No senders verified */
+ memset(sender_address_cache, 0, sizeof(sender_address_cache));
+ memset(sender_domain_cache, 0, sizeof(sender_domain_cache));
++
++#ifdef SUPPORT_DSN
++/* Reset the DSN flags */
++dsn_ret = 0;
++dsn_envid = NULL;
++#endif
++
+ authenticated_sender = NULL;
+ #ifdef EXPERIMENTAL_BRIGHTMAIL
+ bmi_run = 0;
+@@ -2679,6 +2693,10 @@
+ int ptr, size, rc;
+ int c, i;
+ auth_instance *au;
++#ifdef SUPPORT_DSN
++ uschar *orcpt = NULL;
++ int flags;
++#endif
+
+ switch(smtp_read_command(TRUE))
+ {
+@@ -3106,6 +3124,12 @@
+ s = string_cat(s, &size, &ptr, US"-8BITMIME\r\n", 11);
+ }
+
++ #ifdef SUPPORT_DSN
++ /* Advertise DSN support if configured to do so. */
++ if (dsn)
++ s = string_cat(s, &size, &ptr, US"250-DSN\r\n", 9);
++ #endif
++
+ /* Advertise ETRN if there's an ACL checking whether a host is
+ permitted to issue it; a check is made when any host actually tries. */
+
+@@ -3360,6 +3384,42 @@
+ arg_error = TRUE;
+ break;
+
++#ifdef SUPPORT_DSN
++
++ /* Handle the two DSN options, but only if configured to do so
++ * (which will have caused "DSN" to be given in the EHLO
++ * response). The code itself is included only if configured in
++ * at build time. */
++
++ case ENV_MAIL_OPT_RET:
++ /* Check if RET has already been set */
++ if (dsn_ret > 0) {
++ synprot_error(L_smtp_syntax_error, 501, NULL,
++ US"RET can be specified once only");
++ goto COMMAND_LOOP;
++ }
++ dsn_ret = (strcmpic(value, US"HDRS") == 0)? dsn_ret_hdrs :
++ (strcmpic(value, US"FULL") == 0)? dsn_ret_full : 0;
++ DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret);
++ /* Check for invalid invalid value, and exit with error */
++ if (dsn_ret == 0) {
++ synprot_error(L_smtp_syntax_error, 501, NULL,
++ US"Value for RET is invalid");
++ goto COMMAND_LOOP;
++ }
++ break;
++ case ENV_MAIL_OPT_ENVID:
++ /* Check if the dsn envid has been already set */
++ if (dsn_envid != NULL) {
++ synprot_error(L_smtp_syntax_error, 501, NULL,
++ US"ENVID can be specified once only");
++ goto COMMAND_LOOP;
++ }
++ dsn_envid = string_copy(value);
++ DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid);
++ break;
++#endif
++
+ /* Handle the AUTH extension. If the value given is not "<>" and either
+ the ACL says "yes" or there is no ACL but the sending host is
+ authenticated, we set it up as the authenticated sender. However, if the
+@@ -3633,6 +3693,89 @@
+ rcpt_fail_count++;
+ break;
+ }
++
++ #ifdef SUPPORT_DSN
++ /* Set the DSN flags orcpt and dsn_flags from the session*/
++ orcpt = NULL;
++ flags = 0;
++
++ if (esmtp) for(;;)
++ {
++ uschar *name, *value, *end;
++ int size;
++
++ if (!extract_option(&name, &value))
++ {
++ break;
++ }
++
++ if (strcmpic(name, US"ORCPT") == 0)
++ {
++ /* Check whether orcpt has been already set */
++ if (orcpt != NULL) {
++ synprot_error(L_smtp_syntax_error, 501, NULL,
++ US"ORCPT can be specified once only");
++ goto COMMAND_LOOP;
++ }
++ orcpt = string_copy(value);
++ DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", orcpt);
++ }
++
++ else if (strcmpic(name, US"NOTIFY") == 0)
++ {
++ /* Check if the notify flags have been already set */
++ if (flags > 0)
++ {
++ synprot_error(L_smtp_syntax_error, 501, NULL,
++ US"NOTIFY can be specified once only");
++ goto COMMAND_LOOP;
++ }
++ if (strcmpic(value, US"NEVER") == 0) flags |= rf_notify_never; else
++ {
++ uschar *p = value;
++ while (*p != 0)
++ {
++ uschar *pp = p;
++ while (*pp != 0 && *pp != ',') pp++;
++ if (*pp == ',') *pp++ = 0;
++ if (strcmpic(p, US"SUCCESS") == 0) {
++ DEBUG(D_receive) debug_printf("GC: Setting notify success\n");
++ flags |= rf_notify_success;
++ }
++ else if (strcmpic(p, US"FAILURE") == 0) {
++ DEBUG(D_receive) debug_printf("GC: Setting notify failure\n");
++ flags |= rf_notify_failure;
++ }
++ else if (strcmpic(p, US"DELAY") == 0) {
++ DEBUG(D_receive) debug_printf("GC: Setting notify delay\n");
++ flags |= rf_notify_delay;
++ }
++ else
++ {
++ /* Catch any strange values */
++ synprot_error(L_smtp_syntax_error, 501, NULL,
++ US"Invalid value for NOTIFY parameter");
++ goto COMMAND_LOOP;
++ }
++ p = pp;
++ }
++ DEBUG(D_receive) debug_printf("DSN Flags: %x\n", flags);
++ }
++ }
++
++ /* Unknown option. Stick back the terminator characters and break
++ the loop. An error for a malformed address will occur. */
++
++ else
++ {
++ DEBUG(D_receive) debug_printf("Invalid dsn command: %s : %s\n", name, value);
++ name[-1] = ' ';
++ value[-1] = '=';
++ break;
++ }
++ }
++ #endif
++
+
+ /* Apply SMTP rewriting then extract the working address. Don't allow "<>"
+ as a recipient address */
+@@ -3747,6 +3890,24 @@
+ if (user_msg == NULL) smtp_printf("250 Accepted\r\n");
+ else smtp_user_msg(US"250", user_msg);
+ receive_add_recipient(recipient, -1);
++
++ #ifdef SUPPORT_DSN
++
++ /* Set the dsn flags in the recipients_list */
++ if (orcpt != NULL)
++ recipients_list[recipients_count-1].orcpt = orcpt;
++ else
++ recipients_list[recipients_count-1].orcpt = NULL;
++
++ if (flags != 0)
++ recipients_list[recipients_count-1].dsn_flags = flags;
++ else
++ recipients_list[recipients_count-1].dsn_flags = 0;
++ debug_printf("DSN-AJ(smtp-in): orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags);
++
++
++ #endif
++
+ }
+
+ /* The recipient was discarded */
+diff -Naur exim-4.82_RC5.orig/src/spool_in.c exim-4.82_RC5/src/spool_in.c
+--- exim-4.82_RC5.orig/src/spool_in.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/spool_in.c 2013-10-27 21:47:32.000000000 +0100
+@@ -293,6 +293,13 @@
+ spam_score_int = NULL;
+ #endif
+
++#ifdef SUPPORT_DSN
++#ifndef COMPILE_UTILITY
++dsn_ret = 0;
++dsn_envid = NULL;
++#endif /* COMPILE_UTILITY */
++#endif
++
+ /* Generate the full name and open the file. If message_subdir is already
+ set, just look in the given directory. Otherwise, look in both the split
+ and unsplit directories, as for the data file above. */
+@@ -467,6 +474,19 @@
+ case 'd':
+ if (Ustrcmp(p, "eliver_firsttime") == 0)
+ deliver_firsttime = TRUE;
++ #ifdef SUPPORT_DSN
++ #ifndef COMPILE_UTILITY
++ /* Check if the dsn flags have been set in the header file */
++ else if (Ustrncmp(p, "sn_ret", 6) == 0)
++ {
++ dsn_ret= atoi(big_buffer + 8);
++ }
++ else if (Ustrncmp(p, "sn_envid", 8) == 0)
++ {
++ dsn_envid = string_copy(big_buffer + 11);
++ }
++ #endif /* COMPILE_UTILITY */
++ #endif
+ break;
+
+ case 'f':
+@@ -554,7 +574,7 @@
+ tls_in.sni = string_unprinting(string_copy(big_buffer + 9));
+ break;
+ #endif
+-
++
+ default: /* Present because some compilers complain if all */
+ break; /* possibilities are not covered. */
+ }
+@@ -604,6 +624,10 @@
+ {
+ int nn;
+ int pno = -1;
++ #ifdef SUPPORT_DSN
++ int dsn_flags = 0;
++ uschar *orcpt = NULL;
++ #endif
+ uschar *errors_to = NULL;
+ uschar *p;
+
+@@ -672,10 +696,19 @@
+ }
+
+ /* Handle current format Exim 4 spool files */
++ /* Spool file is modified if DSN is supported
++ Original was "address errors_to len(errors_to),pno
++ New for DSN support is now:
++ "address errors_to orcpt len(errors_to),len(orcpt),pno,dsn_flags */
+
+ else if (*p == '#')
+ {
+ int flags;
++
++ #ifndef COMPILE_UTILITY
++ DEBUG(D_deliver) debug_printf("**** SPOOL_IN - Exim 4 standard format spoolfile\n");
++ #endif /* COMPILE_UTILITY */
++
+ (void)sscanf(CS p+1, "%d", &flags);
+
+ if ((flags & 0x01) != 0) /* one_time data exists */
+@@ -688,15 +721,82 @@
+ {
+ p -= len;
+ errors_to = string_copy(p);
++ }
++ }
++
++ *(--p) = 0; /* Terminate address */
++ }
++ #ifdef SUPPORT_DSN
++ else if (*p == '!') /* Handle Exim4 + DSN spool files */
++ {
++ int flags;
++ int temp_dsn_flags;
++
++ #ifndef COMPILE_UTILITY
++ DEBUG(D_deliver) debug_printf("**** SPOOL_IN - C&W DSN format spoolfile\n");
++ #endif /* COMPILE_UTILITY */
++
++ sscanf(CS p+1, "%d,%d", &flags, &temp_dsn_flags);
++
++ if (((flags & 0x01) != 0) || (temp_dsn_flags > 0)) /* one_time data or dsn_flags exist */
++ {
++ int len;
++ int len_orcpt;
++
++ #ifndef COMPILE_UTILITY
++ DEBUG(D_deliver) debug_printf("**** spool_in dsn_flags = 0\n");
++ #endif /* COMPILE_UTILITY */
++
++ dsn_flags = 0;
++
++ while (isdigit(*(--p)) || *p == ',' || *p == '-');
++ sscanf(CS p+1, "%d,%d,%d,%d", &len, &len_orcpt, &pno, &dsn_flags);
++
++ *p = 0;
++ if (len_orcpt > 0)
++ {
++ p -= len_orcpt;
++ orcpt = string_copy(p);
+ }
++ *(--p) = 0; /* change the space to a NULL */
++
++ if (len > 0)
++ {
++ p -= len;
++ errors_to = string_copy(p);
++ }
+ }
+
+ *(--p) = 0; /* Terminate address */
+ }
++ #endif
++ #ifndef COMPILE_UTILITY
++ else
++ {
++ DEBUG(D_deliver) debug_printf("**** SPOOL_IN - No additional fields\n");
++ }
++ #endif /* COMPILE_UTILITY */
++
++ #ifdef SUPPORT_DSN
++ #ifndef COMPILE_UTILITY
++ DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
++ big_buffer, errors_to, orcpt, dsn_flags);
++ #endif /* COMPILE_UTILITY */
++ #endif
++ #ifndef SUPPORT_DSN
++ #ifndef COMPILE_UTILITY
++ DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s|\n",
++ big_buffer, errors_to);
++ #endif /* COMPILE_UTILITY */
++ #endif
+
+ recipients_list[recipients_count].address = string_copy(big_buffer);
+ recipients_list[recipients_count].pno = pno;
+ recipients_list[recipients_count].errors_to = errors_to;
++ #ifdef SUPPORT_DSN
++ recipients_list[recipients_count].orcpt = orcpt;
++ recipients_list[recipients_count].dsn_flags = dsn_flags;
++ #endif
+ }
+
+ /* The remainder of the spool header file contains the headers for the message,
+diff -Naur exim-4.82_RC5.orig/src/spool_out.c exim-4.82_RC5/src/spool_out.c
+--- exim-4.82_RC5.orig/src/spool_out.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/spool_out.c 2013-10-27 21:47:32.000000000 +0100
+@@ -234,6 +234,15 @@
+ if (tls_in.sni != NULL) fprintf(f, "-tls_sni %s\n", string_printing(tls_in.sni));
+ #endif
+
++#ifdef SUPPORT_DSN
++/* Write the dsn flags to the spool header file */
++DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
++if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
++DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret);
++if (dsn_ret != 0) fprintf(f, "-dsn_ret %d\n", dsn_ret);
++#endif
++
++
+ /* To complete the envelope, write out the tree of non-recipients, followed by
+ the list of recipients. These won't be disjoint the first time, when no
+ checking has been done. If a recipient is a "one-time" alias, it is followed by
+@@ -244,14 +253,36 @@
+ for (i = 0; i < recipients_count; i++)
+ {
+ recipient_item *r = recipients_list + i;
+- if (r->pno < 0 && r->errors_to == NULL)
++#ifdef SUPPORT_DSN
++DEBUG(D_deliver) debug_printf("DSN: Flags :%d\n", r->dsn_flags);
++#endif
++ if (r->pno < 0 && r->errors_to == NULL
++ #ifdef SUPPORT_DSN
++ && r->dsn_flags == 0
++ #endif
++ )
+ fprintf(f, "%s\n", r->address);
+ else
+ {
+ uschar *errors_to = (r->errors_to == NULL)? US"" : r->errors_to;
++ #ifdef SUPPORT_DSN
++ uschar *orcpt = (r->orcpt == NULL)? US"" : r->orcpt;
++ fprintf(f, "%s %s %s %d,%d,%d,%d!1\n", r->address, errors_to, orcpt,
++ Ustrlen(errors_to), Ustrlen(orcpt), r->pno, r->dsn_flags);
++ #else
+ fprintf(f, "%s %s %d,%d#1\n", r->address, errors_to,
+ Ustrlen(errors_to), r->pno);
++ #endif
+ }
++
++ #ifdef SUPPORT_DSN
++ DEBUG(D_deliver) debug_printf("DSN :**** SPOOL_OUT - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
++ r->address, r->errors_to, r->orcpt, r->dsn_flags);
++ #endif
++ #ifndef SUPPORT_DSN
++ DEBUG(D_deliver) debug_printf("**** SPOOL_OUT - address: |%s| errorsto: |%s|\n",
++ r->address, r->errors_to);
++ #endif
+ }
+
+ /* Put a blank line before the headers */
+diff -Naur exim-4.82_RC5.orig/src/structs.h exim-4.82_RC5/src/structs.h
+--- exim-4.82_RC5.orig/src/structs.h 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/structs.h 2013-10-27 21:47:32.000000000 +0100
+@@ -282,7 +282,9 @@
+ BOOL verify_sender; /* Use this router when verifying a sender */
+ BOOL uid_set; /* Flag to indicate uid is set */
+ BOOL unseen; /* If TRUE carry on, even after success */
+-
++#ifdef SUPPORT_DSN
++ BOOL dsn_process; /* If TRUE, activate DSN for this router */
++#endif
+ int self_code; /* Encoded version of "self" */
+ uid_t uid; /* Fixed uid value */
+ gid_t gid; /* Fixed gid value */
+@@ -547,6 +549,12 @@
+ uschar *auth_id; /* auth "login" name used by transport */
+ uschar *auth_sndr; /* AUTH arg to SMTP MAIL, used by transport */
+
++ #ifdef SUPPORT_DSN
++ uschar *dsn_orcpt; /* DSN orcpt value */
++ int dsn_flags; /* DSN flags */
++ uschar *dsn_aware; /* DSN aware flag */
++ #endif
++
+ uid_t uid; /* uid for transporting */
+ gid_t gid; /* gid for transporting */
+
+diff -Naur exim-4.82_RC5.orig/src/transport.c exim-4.82_RC5/src/transport.c
+--- exim-4.82_RC5.orig/src/transport.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/transport.c 2013-10-27 21:47:32.000000000 +0100
+@@ -1802,6 +1802,11 @@
+
+ argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
+
++ #ifdef SUPPORT_DSN
++ /* Call with the dsn flag */
++ if (smtp_use_dsn) argv[i++] = US"-MCD";
++ #endif
++
+ if (smtp_authenticated) argv[i++] = US"-MCA";
+
+ #ifdef SUPPORT_TLS
+diff -Naur exim-4.82_RC5.orig/src/transports/smtp.c exim-4.82_RC5/src/transports/smtp.c
+--- exim-4.82_RC5.orig/src/transports/smtp.c 2013-10-27 21:46:25.000000000 +0100
++++ exim-4.82_RC5/src/transports/smtp.c 2013-10-27 21:47:32.000000000 +0100
+@@ -242,6 +242,16 @@
+ #endif
+ };
+
++#ifdef SUPPORT_DSN
++/* some DSN flags for use later */
++
++static int rf_list[] = {rf_notify_never, rf_notify_success,
++ rf_notify_failure, rf_notify_delay };
++
++static uschar *rf_names[] = { "NEVER", "SUCCESS", "FAILURE", "DELAY" };
++#endif
++
++
+
+ /* Local statics */
+
+@@ -1079,6 +1089,27 @@
+ else if (new[0] != 0) local_authenticated_sender = new;
+ }
+
++#ifdef SUPPORT_DSN
++/* Add any DSN flags to the mail command */
++
++if (smtp_use_dsn)
++ {
++ uschar *p = buffer;
++ if (dsn_ret == dsn_ret_hdrs)
++ {
++ strcpy(p, " RET=HDRS");
++ while (*p) p++;
++ }
++ else if (dsn_ret == dsn_ret_full)
++ {
++ strcpy(p, " RET=FULL");
++ while (*p) p++;
++ }
++ if (dsn_envid != NULL)
++ string_format(p, sizeof(buffer) - (p-buffer), " ENVID=%s", dsn_envid);
++ }
++#endif
++
+ /* Add the authenticated sender address if present */
+
+ if ((smtp_authenticated || ob->authenticated_sender_force) &&
+@@ -1587,6 +1618,14 @@
+ {DEBUG(D_transport) debug_printf("PRDR usable\n");}
+ #endif
+
++ #ifdef SUPPORT_DSN
++ /* Note if the server supports DSN */
++ smtp_use_dsn = dsn &&
++ esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0,
++ PCRE_EOPT, NULL, 0) >= 0;
++ DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
++ #endif
++
+ /* Note if the response to EHLO specifies support for the AUTH extension.
+ If it has, check that this host is one we want to authenticate to, and do
+ the business. The host name and address must be available when the
+@@ -1746,18 +1785,66 @@
+ int count;
+ BOOL no_flush;
+
++ #ifdef SUPPORT_DSN
++ /* philb - set dsn_aware flag for this recipient */
++ if(smtp_use_dsn)
++ addr->dsn_aware = string_copy("Y");
++ else
++ addr->dsn_aware = string_copy("N");
++ #endif
++
+ if (addr->transport_return != PENDING_DEFER) continue;
+
+ address_count++;
+ no_flush = smtp_use_pipelining && (!mua_wrapper || addr->next != NULL);
+
++ #ifdef SUPPORT_DSN
++ /* Add any DSN flags to the rcpt command and add to the sent string */
++
++ p = buffer;
++ *p = 0;
++
++ if (smtp_use_dsn)
++ {
++ if ((addr->dsn_flags & rf_dsnflags) != 0)
++ {
++ int i;
++ BOOL first = TRUE;
++ strcpy(p, " NOTIFY=");
++ while (*p) p++;
++ for (i = 0; i < 4; i++)
++ {
++ if ((addr->dsn_flags & rf_list[i]) != 0)
++ {
++ if (!first) *p++ = ',';
++ first = FALSE;
++ strcpy(p, rf_names[i]);
++ while (*p) p++;
++ }
++ }
++ }
++
++ if (addr->dsn_orcpt != NULL)
++ string_format(p, sizeof(buffer) - (p-buffer), " ORCPT=%s",
++ addr->dsn_orcpt);
++ }
++
++ #endif
++
++
+ /* Now send the RCPT command, and process outstanding responses when
+ necessary. After a timeout on RCPT, we just end the function, leaving the
+ yield as OK, because this error can often mean that there is a problem with
+ just one address, so we don't want to delay the host. */
+
++ #ifdef SUPPORT_DSN
++ count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
++ transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr, buffer);
++ #else
+ count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n",
+ transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr);
++ #endif
++
+ if (count < 0) goto SEND_FAILED;
+ if (count > 0)
+ {