1 diff -urN exim-4.63-orig/README.DSN exim-4.63-dsn/README.DSN
2 --- exim-4.63-orig/README.DSN 1970-01-01 01:00:00.000000000 +0100
3 +++ exim-4.63-dsn/README.DSN 2006-09-12 11:47:24.000000000 +0100
8 +This patch is free software; you can redistribute it and/or modify
9 +it under the terms of the GNU General Public License as published by
10 +the Free Software Foundation; either version 2 of the License, or
11 +(at your option) any later version.
13 +This patch is distributed in the hope that it will be useful,
14 +but WITHOUT ANY WARRANTY; without even the implied warranty of
15 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 +GNU General Public License for more details.
18 +You should have received a copy of the GNU General Public License
19 +along with this patch; if not, write to the Free Software
20 +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
24 +cd into the source tree for a vanilla exim
26 +patch -p1 </path/to/patch/file.patch
29 +[root@linuxbuild exim-4.60-test]# patch -p1 <../exim.dsn.patch.460
32 +patching file README.DSN
33 +patching file src/config.h.defaults
34 +patching file src/deliver.c
35 +patching file src/exim.c
36 +patching file src/exim.h
37 +patching file src/globals.c
38 +patching file src/globals.h
39 +patching file src/local_scan.h
40 +patching file src/macros.h
41 +patching file src/readconf.c
42 +patching file src/route.c
43 +patching file src/smtp_in.c
44 +patching file src/spool_in.c
45 +patching file src/spool_out.c
46 +patching file src/structs.h
47 +patching file src/transport.c
48 +patching file src/transports/smtp.c
51 +This patch can be included / excluded from the compilation by use of the #define SUPPORT_DSN
52 +which gets added into src/config.h.defaults & src/EDITME by the patch.
57 +The facility (once compiled in) can be turned on for a particular router via the
58 +dsn_process directive Eg :-
61 + driver = manualroute
62 + domains = +relay_to_domains
63 + condition = ${if eq {${lc:$sender_address_domain}}\
68 + hide route_data = ${lc:${extract{mailHost}{$address_data}{$value}{}}}
69 + transport = remote_smtp
71 +Exim will produce 1 of 2 DSN's back to the originator, or pass on the DSN request.
72 +The 2 DSN's will either contain (relayed via non "Remote SMTP" router) or
73 +(relayed to non-DSN-aware mailer) depending on if the delivery was VIA an SMTP
80 +The original work for the patch was done by Philip Hazel in Exim 3
82 +The extract was taken and re-applied to Exim 4 by the following :-
83 +Phil Bingham (phil.bingham@cwipapps.net)
84 +Steve Falla (steve.falla@cwipapps.net)
85 +Ray Edah (ray.edah@cwipapps.net)
86 +Andrew Johnson (andrew.johnson@cwippaps.net)
87 +Adrian Hungate (adrian.hungate@cwipapps.net)
91 +Andrey J. Melnikoff (TEMHOTA) (temnota@kmv.ru)
97 +14-Apr-2006 : Changed subject to "Delivery Status Notification"
99 +17-May-2006 : debug_printf in spool-in.c were not wrapped with #ifndef COMPILE_UTILITY
100 + thanks to Andrey J. Melnikoff for this information
104 +Support for this patch (limited though it is) will only be provided through the SourceForge
105 +project page (http://sourceforge.net/projects/eximdsn/)
108 +Andrew Johnson Cable & Wireless
109 diff -urN exim-4.63-orig/src/config.h.defaults exim-4.63-dsn/src/config.h.defaults
110 --- exim-4.63-orig/src/config.h.defaults 2006-07-31 15:19:48.000000000 +0100
111 +++ exim-4.63-dsn/src/config.h.defaults 2006-09-12 11:47:24.000000000 +0100
113 #define SUPPORT_MOVE_FROZEN_MESSAGES
117 #define SUPPORT_TRANSLATE_IP_ADDRESS
119 #define SYSLOG_LOG_PID
120 diff -urN exim-4.63-orig/src/deliver.c exim-4.63-dsn/src/deliver.c
121 --- exim-4.63-orig/src/deliver.c 2006-07-31 15:19:48.000000000 +0100
122 +++ exim-4.63-dsn/src/deliver.c 2006-09-12 11:47:24.000000000 +0100
124 static address_item *addr_remote = NULL;
125 static address_item *addr_route = NULL;
126 static address_item *addr_succeed = NULL;
128 +static address_item *addr_dsntmp = NULL;
131 static FILE *message_log = NULL;
132 static BOOL update_spool;
133 @@ -2866,6 +2869,15 @@
139 + if (addr == NULL) break;
140 + addr->dsn_aware = (*ptr)? string_copy(ptr) : string_copy(" ");
142 + DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %s\n", addr->dsn_aware);
149 @@ -3935,6 +3947,15 @@
154 + if (addr->dsn_aware == NULL)
155 + addr->dsn_aware = string_copy(" ");
156 + DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %s\n", addr->dsn_aware);
157 + sprintf(big_buffer, "D%s", addr->dsn_aware);
158 + DEBUG(D_deliver) debug_printf("DSN write: big_buffer = %s (%d)\n", big_buffer, strlen(big_buffer)+1);
159 + write(fd, big_buffer, strlen(big_buffer)+1);
162 /* Retry information: for most success cases this will be null. */
164 for (r = addr->retries; r != NULL; r = r->next)
165 @@ -5072,6 +5093,14 @@
167 new->onetime_parent = recipients_list[r->pno].address;
170 + /* If DSN support is enabled, set the dsn flags and the original receipt
171 + to be passed on to other DSN enabled MTAs */
172 + new->dsn_flags = r->dsn_flags & rf_dsnflags;
173 + new->dsn_orcpt = r->orcpt;
174 + debug_printf("DSN (deliver): orcpt: %s flags: %d\n", new->dsn_orcpt, new->dsn_flags);
177 switch (process_recipients)
179 /* RECIP_DEFER is set when a system filter freezes a message. */
180 @@ -5959,6 +5988,12 @@
181 regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
185 + /* Set the regex to check for DSN support on remote MTA */
186 + if (regex_DSN == NULL) regex_DSN =
187 + regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
190 /* Now sort the addresses if required, and do the deliveries. The yield of
191 do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
192 cannot be delivered in one transaction. */
193 @@ -6063,6 +6098,179 @@
195 else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed);
198 +/* ********** philb - Send DSN for successful messages */
200 +addr_dsntmp = addr_succeed;
202 +while(addr_dsntmp != NULL)
204 + BOOL dsn_sendmessage = FALSE;
205 + uschar dsnmsgbuf[4096];
208 + debug_printf("DSN: processing router : %s\n", addr_dsntmp->router->name);
211 + debug_printf("DSN: processing successful delivery address: %s\n", addr_dsntmp->address);
213 + if (testflag(addr_dsntmp, af_ignore_error))
216 + debug_printf("DSN: Ignore error for: %s\n", addr_dsntmp->address);
220 + DEBUG(D_deliver) debug_printf("DSN: Checking Flag\n");
221 + if (addr_dsntmp->dsn_aware == NULL) {
222 + DEBUG(D_deliver) debug_printf("DSN: dsn_aware was NULL, setting to space at %s %d\n", __FILE__, __LINE__);
223 + addr_dsntmp->dsn_aware = string_copy(" ");
225 + DEBUG(D_deliver) debug_printf("DSN: Sender_address: %s\n", sender_address);
226 + DEBUG(D_deliver) debug_printf("DSN: orcpt: %s flags: %d\n", addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags);
227 + DEBUG(D_deliver) debug_printf("DSN: envid: %s ret: %d\n", dsn_envid, dsn_ret);
228 + DEBUG(D_deliver) debug_printf("DSN: Remote SMTP server supports DSN: %s\n", addr_dsntmp->dsn_aware);
230 + /* Process the flags */
231 + if((addr_dsntmp->dsn_flags & rf_dsnflags) != 0)
233 + /* We've got at least one flag set */
235 + /* set flag so we don't send bounces */
236 + setflag(addr_dsntmp, af_ignore_error);
238 + if((addr_dsntmp->dsn_flags & rf_notify_never) != 0)
240 + DEBUG(D_deliver) debug_printf("DSN: NEVER FLAG\n");
242 + /* nothing to do here */
245 + if((addr_dsntmp->dsn_flags & rf_notify_success) != 0)
247 + DEBUG(D_deliver) debug_printf("DSN: SUCCESS FLAG\n");
249 + dsn_sendmessage = TRUE;
252 + if((addr_dsntmp->dsn_flags & rf_notify_failure) != 0)
254 + DEBUG(D_deliver) debug_printf("DSN: FAILURE FLAG\n");
256 + /* allow bounce messages */
257 + clearflag(addr_dsntmp, af_ignore_error);
260 + if((addr_dsntmp->dsn_flags & rf_notify_delay) != 0)
262 + DEBUG(D_deliver) debug_printf("DSN: DELAY FLAG\n");
264 + /* hmm, what to do here? */
268 + if ((addr_dsntmp->dsn_aware != 0) && (addr_dsntmp->dsn_aware[0] != 'Y') && (dsn_sendmessage == TRUE) && (addr_dsntmp->router->dsn_process == TRUE))
273 + /* remote MTA does not support DSN, so we need to send message */
275 + /* create exim process to send message */
276 + pid = child_open_exim(&fd);
278 + DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %d\n", pid);
280 + if (pid < 0) /* Creation of child failed */
282 + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to "
283 + "create child process to send failure message: %s", getpid(),
284 + getppid(), strerror(errno));
286 + DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n");
289 + else /* Creation of child succeeded */
291 + FILE *f = fdopen(fd, "wb");
292 + int topt = topt_add_return_path;
293 + uschar boundaryStr[64];
295 + DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address);
297 + /* build unique id for MIME boundary */
298 + snprintf(boundaryStr, 63, "%d-cwdsn-%d", pid, rand());
299 + DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr);
301 + /* if the sender doesn't want the whole message returned, don't send the body */
302 + if (dsn_ret != dsn_ret_full) topt |= topt_no_body;
304 + if (errors_reply_to != NULL) fprintf(f,"Reply-To: %s\n", errors_reply_to);
306 + fprintf(f,"Auto-Submitted: auto-generated\n");
307 + fprintf(f,"From: Mail Delivery System <Mailer-Daemon@%s>\n", qualify_domain_sender);
308 + fprintf(f,"To: %s\n", sender_address);
309 + fprintf(f,"Subject: Delivery Status Notification\n");
310 + fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr);
311 + fprintf(f,"MIME-Version: 1.0\n\n");
313 + fprintf(f,"--%s\n", boundaryStr);
314 + fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n");
316 + fprintf(f,"This message was created automatically by mail delivery software.\n");
317 + fprintf(f," ----- The following addresses had successful delivery notifications -----\n");
318 +/* AH: added specific message for non "Remote SMTP" situations */
319 + if (addr_dsntmp->dsn_aware[0] == 'N') {
320 + fprintf(f,"<%s> (relayed to non-DSN-aware mailer)\n\n", addr_dsntmp->address);
322 + fprintf(f,"<%s> (relayed via non \"Remote SMTP\" router)\n\n", addr_dsntmp->address);
325 + fprintf(f,"--%s\n", boundaryStr);
326 + fprintf(f,"Content-type: message/delivery-status\n\n");
328 + if (dsn_envid) { /* Test for NULL added by GC */
329 + fprintf(f,"Original-Envelope-Id: %s\n", dsn_envid);
331 + fprintf(f,"Reporting-MTA: dns; %s\n", qualify_domain_sender);
332 + if (addr_dsntmp->dsn_orcpt) { /* Test for NULL added by GC */
333 + fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt);
335 + fprintf(f,"Action: delivered\n\n");
337 + fprintf(f,"--%s\n", boundaryStr);
338 + fprintf(f,"Content-type: message/rfc822\n\n");
341 + transport_filter_argv = NULL; /* Just in case */
342 + return_path = sender_address; /* In case not previously set */
344 + /* Write the original email out */
345 + transport_write_message(NULL, fileno(f), topt, 2048, NULL, NULL, NULL, NULL, NULL, 0);
349 + fprintf(f,"--%s--\n", boundaryStr);
353 + rc = child_close(pid, 0); /* Waits for child to close, no timeout */
357 + { if (addr_dsntmp->router->dsn_process == TRUE)
358 + DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message ***\n");
359 + if (addr_dsntmp->router->dsn_process == FALSE)
360 + DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message (gagged) ***\n");
364 + addr_dsntmp = addr_dsntmp->next;
367 +/* ********** philb - end of mod */
370 /* If any addresses failed, we must send a message to somebody, unless
371 af_ignore_error is set, in which case no action is taken. It is possible for
372 several messages to get sent if there are addresses with different
373 diff -urN exim-4.63-orig/src/EDITME exim-4.63-dsn/src/EDITME
374 --- exim-4.63-orig/src/EDITME 2006-07-31 15:19:48.000000000 +0100
375 +++ exim-4.63-dsn/src/EDITME 2006-09-12 11:47:24.000000000 +0100
377 # least one type of lookup. You should consider whether you want to build
378 # the Exim monitor or not.
383 #------------------------------------------------------------------------------
384 # These settings determine which individual router drivers are included in the
385 diff -urN exim-4.63-orig/src/exim.c exim-4.63-dsn/src/exim.c
386 --- exim-4.63-orig/src/exim.c 2006-07-31 15:19:48.000000000 +0100
387 +++ exim-4.63-dsn/src/exim.c 2006-09-12 11:47:24.000000000 +0100
389 #ifdef EXPERIMENTAL_DOMAINKEYS
390 fprintf(f, " Experimental_DomainKeys");
393 + fprintf(f, " C&W_DSN_1.2");
397 fprintf(f, "Lookups:");
398 @@ -2192,6 +2195,16 @@
403 + /* -MCD: set the smtp_use_dsn flag; this indicates that the host
404 + that exim is connected to supports the esmtp extension DSN */
405 + else if (strcmp(argrest, "CD") == 0)
407 + smtp_use_dsn = TRUE;
412 /* -MCP: set the smtp_use_pipelining flag; this is useful only when
413 it preceded -MC (see above) */
415 diff -urN exim-4.63-orig/src/globals.c exim-4.63-dsn/src/globals.c
416 --- exim-4.63-orig/src/globals.c 2006-07-31 15:19:48.000000000 +0100
417 +++ exim-4.63-dsn/src/globals.c 2006-09-12 11:47:24.000000000 +0100
419 uschar *tls_verify_hosts = NULL;
424 +uschar *dsn_envid = NULL;
426 +const pcre *regex_DSN = NULL;
427 +BOOL smtp_use_dsn = FALSE;
430 /* Input-reading functions for messages, so we can use special ones for
431 incoming TCP/IP. The defaults use stdin. We never need these for any
437 + NULL, /* dsn_orcpt */
439 + NULL, /* dsn_aware */
441 (uid_t)(-1), /* uid */
442 (gid_t)(-1), /* gid */
445 TRUE, /* verify_sender */
449 + FALSE, /* dsn_process */
452 self_freeze, /* self_code */
453 (uid_t)(-1), /* uid */
455 NULL, /* transport instance */
456 NULL, /* pass_router */
457 NULL /* redirect_router */
461 ip_address_item *running_interfaces = NULL;
462 diff -urN exim-4.63-orig/src/globals.h exim-4.63-dsn/src/globals.h
463 --- exim-4.63-orig/src/globals.h 2006-07-31 15:19:48.000000000 +0100
464 +++ exim-4.63-dsn/src/globals.h 2006-09-12 11:47:24.000000000 +0100
466 extern uschar *tls_verify_hosts; /* Mandatory client verification */
470 +extern BOOL dsn; /* FALSE if DSN not to be used */
471 +extern uschar *dsn_envid; /* DSN envid string */
472 +extern int dsn_ret; /* DSN ret type*/
473 +extern const pcre *regex_DSN; /* For recognizing DSN settings */
474 +extern BOOL smtp_use_dsn; /* Global for passed connections */
477 /* Input-reading functions for messages, so we can use special ones for
479 diff -urN exim-4.63-orig/src/local_scan.h exim-4.63-dsn/src/local_scan.h
480 --- exim-4.63-orig/src/local_scan.h 2006-07-31 15:19:48.000000000 +0100
481 +++ exim-4.63-dsn/src/local_scan.h 2006-09-12 11:47:24.000000000 +0100
483 field is always NULL except for one_time aliases that had errors_to on the
484 routers that generated them. */
486 +/* Added the dsn attributes orcpt and dsn_flags for DSN support*/
488 typedef struct recipient_item {
489 uschar *address; /* the recipient address */
490 int pno; /* parent number for "one_time" alias, or -1 */
491 + uschar *orcpt; /* DSN orcpt */
492 + int dsn_flags; /* DSN flags */
493 uschar *errors_to; /* the errors_to address or NULL */
494 #ifdef EXPERIMENTAL_BRIGHTMAIL
496 diff -urN exim-4.63-orig/src/macros.h exim-4.63-dsn/src/macros.h
497 --- exim-4.63-orig/src/macros.h 2006-07-31 15:19:48.000000000 +0100
498 +++ exim-4.63-dsn/src/macros.h 2006-09-12 11:47:24.000000000 +0100
500 #define topt_no_body 0x040 /* Omit body */
501 #define topt_escape_headers 0x080 /* Apply escape check to headers */
503 +/* Flags for recipient_block, used in DSN support */
505 +#define rf_onetime 0x01 /* A one-time alias */
506 +#define rf_notify_never 0x02 /* NOTIFY= settings */
507 +#define rf_notify_success 0x04
508 +#define rf_notify_failure 0x08
509 +#define rf_notify_delay 0x10
511 +#define rf_dsnflags (rf_notify_never | rf_notify_success | \
512 + rf_notify_failure | rf_notify_delay)
516 +#define dsn_ret_full 1
517 +#define dsn_ret_hdrs 2
519 /* Codes for the host_find_failed option. */
522 diff -urN exim-4.63-orig/src/readconf.c exim-4.63-dsn/src/readconf.c
523 --- exim-4.63-orig/src/readconf.c 2006-07-31 15:19:48.000000000 +0100
524 +++ exim-4.63-dsn/src/readconf.c 2006-09-12 11:47:24.000000000 +0100
526 { "dns_ipv4_lookup", opt_stringptr, &dns_ipv4_lookup },
527 { "dns_retrans", opt_time, &dns_retrans },
528 { "dns_retry", opt_int, &dns_retry },
530 + { "dsn", opt_bool, &dsn },
532 /* This option is now a no-op, retained for compability */
533 { "drop_cr", opt_bool, &drop_cr },
534 /*********************************************************/
535 diff -urN exim-4.63-orig/src/receive.c exim-4.63-dsn/src/receive.c
536 --- exim-4.63-orig/src/receive.c 2006-07-31 15:19:48.000000000 +0100
537 +++ exim-4.63-dsn/src/receive.c 2006-09-12 11:47:24.000000000 +0100
539 memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
542 +/* memset added by GC to blank dsn records, etc. */
543 +memset(&recipients_list[recipients_count], 0, sizeof(recipient_item));
544 recipients_list[recipients_count].address = recipient;
545 recipients_list[recipients_count].pno = pno;
546 #ifdef EXPERIMENTAL_BRIGHTMAIL
547 diff -urN exim-4.63-orig/src/route.c exim-4.63-dsn/src/route.c
548 --- exim-4.63-orig/src/route.c 2006-07-31 15:19:48.000000000 +0100
549 +++ exim-4.63-dsn/src/route.c 2006-09-12 11:47:24.000000000 +0100
551 (void *)offsetof(router_instance, domains) },
552 { "driver", opt_stringptr|opt_public,
553 (void *)offsetof(router_instance, driver_name) },
555 + { "dsn_process", opt_bool|opt_public,
556 + (void *)offsetof(router_instance, dsn_process) },
558 { "errors_to", opt_stringptr|opt_public,
559 (void *)(offsetof(router_instance, errors_to)) },
560 { "expn", opt_bool|opt_public,
563 if (r->pass_router_name != NULL)
564 set_router(r, r->pass_router_name, &(r->pass_router), TRUE);
567 + if (r->dsn_process == FALSE)
568 + DEBUG(D_route) debug_printf("%s router skipping DSN - add dsn_process to router\n", r->name);
569 + if (r->dsn_process == TRUE)
570 + DEBUG(D_route) debug_printf("%s router performing DSN \n", r->name);
575 @@ -1408,7 +1419,10 @@
577 copyflag(new, addr, af_propagate);
578 new->p.address_data = addr->p.address_data;
581 + new->dsn_flags = addr->dsn_flags;
582 + new->dsn_orcpt = addr->dsn_orcpt;
585 /* As it has turned out, we haven't set headers_add or headers_remove for the
586 * clone. Thinking about it, it isn't entirely clear whether they should be
587 diff -urN exim-4.63-orig/src/smtp_in.c exim-4.63-dsn/src/smtp_in.c
588 --- exim-4.63-orig/src/smtp_in.c 2006-07-31 15:19:48.000000000 +0100
589 +++ exim-4.63-dsn/src/smtp_in.c 2006-09-12 11:47:24.000000000 +0100
591 sender_verified_list = NULL; /* No senders verified */
592 memset(sender_address_cache, 0, sizeof(sender_address_cache));
593 memset(sender_domain_cache, 0, sizeof(sender_domain_cache));
596 +/* Reset the DSN flags */
601 authenticated_sender = NULL;
602 #ifdef EXPERIMENTAL_BRIGHTMAIL
604 @@ -2229,6 +2236,10 @@
609 + uschar *orcpt = NULL;
613 switch(smtp_read_command(TRUE))
615 @@ -2632,6 +2643,12 @@
617 s = string_cat(s, &size, &ptr, US"250-8BITMIME\r\n", 14);
620 + /* Advertise DSN support if configured to do so. */
622 + s = string_cat(s, &size, &ptr, US"250-DSN\r\n", 9);
625 /* Advertise ETRN if there's an ACL checking whether a host is
626 permitted to issue it; a check is made when any host actually tries. */
628 @@ -2823,6 +2840,43 @@
629 (strcmpic(value, US"8BITMIME") == 0 ||
630 strcmpic(value, US"7BIT") == 0)) {}
634 + /* Handle the two DSN options, but only if configured to do so (which
635 + will have caused "DSN" to be given in the EHLO response). The code itself
636 + is included only if configured in at build time. */
638 + else if (dsn && strcmpic(name, US"RET") == 0)
640 + /* Check if RET has already been set */
642 + synprot_error(L_smtp_syntax_error, 501, NULL,
643 + US"RET can be specified once only");
646 + dsn_ret = (strcmpic(value, US"HDRS") == 0)? dsn_ret_hdrs :
647 + (strcmpic(value, US"FULL") == 0)? dsn_ret_full : 0;
648 + DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret);
649 + /* Check for invalid invalid value, and exit with error */
650 + if (dsn_ret == 0) {
651 + synprot_error(L_smtp_syntax_error, 501, NULL,
652 + US"Value for RET is invalid");
656 + else if (dsn && strcmpic(name, US"ENVID") == 0)
658 + /* Check if the dsn envid has been already set */
659 + if (dsn_envid != NULL) {
660 + synprot_error(L_smtp_syntax_error, 501, NULL,
661 + US"ENVID can be specified once only");
664 + dsn_envid = string_copy(value);
665 + DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid);
669 /* Handle the AUTH extension. If the value given is not "<>" and either
670 the ACL says "yes" or there is no ACL but the sending host is
671 authenticated, we set it up as the authenticated sender. However, if the
672 @@ -3070,6 +3124,89 @@
678 + /* Set the DSN flags orcpt and dsn_flags from the session*/
684 + uschar *name, *value, *end;
687 + if (!extract_option(&name, &value))
692 + if (strcmpic(name, US"ORCPT") == 0)
694 + /* Check whether orcpt has been already set */
695 + if (orcpt != NULL) {
696 + synprot_error(L_smtp_syntax_error, 501, NULL,
697 + US"ORCPT can be specified once only");
700 + orcpt = string_copy(value);
701 + DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", orcpt);
704 + else if (strcmpic(name, US"NOTIFY") == 0)
706 + /* Check if the notify flags have been already set */
709 + synprot_error(L_smtp_syntax_error, 501, NULL,
710 + US"NOTIFY can be specified once only");
713 + if (strcmpic(value, US"NEVER") == 0) flags |= rf_notify_never; else
719 + while (*pp != 0 && *pp != ',') pp++;
720 + if (*pp == ',') *pp++ = 0;
721 + if (strcmpic(p, US"SUCCESS") == 0) {
722 + DEBUG(D_receive) debug_printf("GC: Setting notify success\n");
723 + flags |= rf_notify_success;
725 + else if (strcmpic(p, US"FAILURE") == 0) {
726 + DEBUG(D_receive) debug_printf("GC: Setting notify failure\n");
727 + flags |= rf_notify_failure;
729 + else if (strcmpic(p, US"DELAY") == 0) {
730 + DEBUG(D_receive) debug_printf("GC: Setting notify delay\n");
731 + flags |= rf_notify_delay;
735 + /* Catch any strange values */
736 + synprot_error(L_smtp_syntax_error, 501, NULL,
737 + US"Invalid value for NOTIFY parameter");
742 + DEBUG(D_receive) debug_printf("DSN Flags: %x\n", flags);
746 + /* Unknown option. Stick back the terminator characters and break
747 + the loop. An error for a malformed address will occur. */
751 + DEBUG(D_receive) debug_printf("Invalid dsn command: %s : %s\n", name, value);
760 /* Apply SMTP rewriting then extract the working address. Don't allow "<>"
761 as a recipient address */
762 @@ -3176,6 +3313,24 @@
764 smtp_printf("250 Accepted\r\n");
765 receive_add_recipient(recipient, -1);
769 + /* Set the dsn flags in the recipients_list */
771 + recipients_list[recipients_count-1].orcpt = orcpt;
773 + recipients_list[recipients_count-1].orcpt = NULL;
776 + recipients_list[recipients_count-1].dsn_flags = flags;
778 + recipients_list[recipients_count-1].dsn_flags = 0;
779 + debug_printf("DSN-AJ(smtp-in): orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags);
786 /* The recipient was discarded */
787 diff -urN exim-4.63-orig/src/spool_in.c exim-4.63-dsn/src/spool_in.c
788 --- exim-4.63-orig/src/spool_in.c 2006-07-31 15:19:48.000000000 +0100
789 +++ exim-4.63-dsn/src/spool_in.c 2006-09-12 11:47:24.000000000 +0100
791 spam_score_int = NULL;
795 +#ifndef COMPILE_UTILITY
798 +#endif /* COMPILE_UTILITY */
801 /* Generate the full name and open the file. If message_subdir is already
802 set, just look in the given directory. Otherwise, look in both the split
803 and unsplit directories, as for the data file above. */
805 tls_peerdn = string_copy(big_buffer + 12);
809 + #ifndef COMPILE_UTILITY
810 + /* Check if the dsn flags have been set in the header file */
811 + else if (Ustrncmp(big_buffer, "-dsn_ret", 8) == 0)
813 + dsn_ret= atoi(big_buffer + 8);
815 + else if (Ustrncmp(big_buffer, "-dsn_envid", 10) == 0)
817 + dsn_envid = string_copy(big_buffer + 11);
819 + #endif /* COMPILE_UTILITY */
823 /* We now record the port number after the address, separated by a
824 dot. For compatibility during upgrading, do nothing if there
825 isn't a value (it gets left at zero). */
832 + uschar *orcpt = NULL;
834 uschar *errors_to = NULL;
837 @@ -626,10 +652,19 @@
840 /* Handle current format Exim 4 spool files */
841 + /* Spool file is modified if DSN is supported
842 + Original was "address errors_to len(errors_to),pno
843 + New for DSN support is now:
844 + "address errors_to orcpt len(errors_to),len(orcpt),pno,dsn_flags */
850 + #ifndef COMPILE_UTILITY
851 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - Exim 4 standard format spoolfile\n");
852 + #endif /* COMPILE_UTILITY */
854 (void)sscanf(CS p+1, "%d", &flags);
856 if ((flags & 0x01) != 0) /* one_time data exists */
857 @@ -642,15 +677,82 @@
860 errors_to = string_copy(p);
864 + *(--p) = 0; /* Terminate address */
867 + else if (*p == '!') /* Handle Exim4 + DSN spool files */
870 + int temp_dsn_flags;
872 + #ifndef COMPILE_UTILITY
873 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - C&W DSN format spoolfile\n");
874 + #endif /* COMPILE_UTILITY */
876 + sscanf(CS p+1, "%d,%d", &flags, &temp_dsn_flags);
878 + if (((flags & 0x01) != 0) || (temp_dsn_flags > 0)) /* one_time data or dsn_flags exist */
883 + #ifndef COMPILE_UTILITY
884 + DEBUG(D_deliver) debug_printf("**** spool_in dsn_flags = 0\n");
885 + #endif /* COMPILE_UTILITY */
889 + while (isdigit(*(--p)) || *p == ',' || *p == '-');
890 + sscanf(CS p+1, "%d,%d,%d,%d", &len, &len_orcpt, &pno, &dsn_flags);
896 + orcpt = string_copy(p);
898 + *(--p) = 0; /* change the space to a NULL */
903 + errors_to = string_copy(p);
907 *(--p) = 0; /* Terminate address */
910 + #ifndef COMPILE_UTILITY
913 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - No additional fields\n");
915 + #endif /* COMPILE_UTILITY */
918 + #ifndef COMPILE_UTILITY
919 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
920 + big_buffer, errors_to, orcpt, dsn_flags);
921 + #endif /* COMPILE_UTILITY */
923 + #ifndef SUPPORT_DSN
924 + #ifndef COMPILE_UTILITY
925 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s|\n",
926 + big_buffer, errors_to);
927 + #endif /* COMPILE_UTILITY */
930 recipients_list[recipients_count].address = string_copy(big_buffer);
931 recipients_list[recipients_count].pno = pno;
932 recipients_list[recipients_count].errors_to = errors_to;
934 + recipients_list[recipients_count].orcpt = orcpt;
935 + recipients_list[recipients_count].dsn_flags = dsn_flags;
939 /* The remainder of the spool header file contains the headers for the message,
940 diff -urN exim-4.63-orig/src/spool_out.c exim-4.63-dsn/src/spool_out.c
941 --- exim-4.63-orig/src/spool_out.c 2006-07-31 15:19:48.000000000 +0100
942 +++ exim-4.63-dsn/src/spool_out.c 2006-09-12 11:47:24.000000000 +0100
944 if (tls_peerdn != NULL) fprintf(f, "-tls_peerdn %s\n", tls_peerdn);
948 +/* Write the dsn flags to the spool header file */
949 +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
950 +if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
951 +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret);
952 +if (dsn_ret != 0) fprintf(f, "-dsn_ret %d\n", dsn_ret);
956 /* To complete the envelope, write out the tree of non-recipients, followed by
957 the list of recipients. These won't be disjoint the first time, when no
958 checking has been done. If a recipient is a "one-time" alias, it is followed by
959 @@ -253,14 +262,36 @@
960 for (i = 0; i < recipients_count; i++)
962 recipient_item *r = recipients_list + i;
963 - if (r->pno < 0 && r->errors_to == NULL)
965 +DEBUG(D_deliver) debug_printf("DSN: Flags :%d\n", r->dsn_flags);
967 + if (r->pno < 0 && r->errors_to == NULL
969 + && r->dsn_flags == 0
972 fprintf(f, "%s\n", r->address);
975 uschar *errors_to = (r->errors_to == NULL)? US"" : r->errors_to;
977 + uschar *orcpt = (r->orcpt == NULL)? US"" : r->orcpt;
978 + fprintf(f, "%s %s %s %d,%d,%d,%d!1\n", r->address, errors_to, orcpt,
979 + Ustrlen(errors_to), Ustrlen(orcpt), r->pno, r->dsn_flags);
981 fprintf(f, "%s %s %d,%d#1\n", r->address, errors_to,
982 Ustrlen(errors_to), r->pno);
987 + DEBUG(D_deliver) debug_printf("DSN :**** SPOOL_OUT - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
988 + r->address, r->errors_to, r->orcpt, r->dsn_flags);
990 + #ifndef SUPPORT_DSN
991 + DEBUG(D_deliver) debug_printf("**** SPOOL_OUT - address: |%s| errorsto: |%s|\n",
992 + r->address, r->errors_to);
996 /* Put a blank line before the headers */
997 diff -urN exim-4.63-orig/src/structs.h exim-4.63-dsn/src/structs.h
998 --- exim-4.63-orig/src/structs.h 2006-07-31 15:19:48.000000000 +0100
999 +++ exim-4.63-dsn/src/structs.h 2006-09-12 11:47:24.000000000 +0100
1001 BOOL verify_sender; /* Use this router when verifying a sender */
1002 BOOL uid_set; /* Flag to indicate uid is set */
1003 BOOL unseen; /* If TRUE carry on, even after success */
1006 + BOOL dsn_process; /* If TRUE, activate DSN for this router */
1008 int self_code; /* Encoded version of "self" */
1009 uid_t uid; /* Fixed uid value */
1010 gid_t gid; /* Fixed gid value */
1011 @@ -560,6 +562,12 @@
1012 uschar *peerdn; /* DN of server's certificate */
1015 + #ifdef SUPPORT_DSN
1016 + uschar *dsn_orcpt; /* DSN orcpt value */
1017 + int dsn_flags; /* DSN flags */
1018 + uschar *dsn_aware; /* DSN aware flag */
1021 uid_t uid; /* uid for transporting */
1022 gid_t gid; /* gid for transporting */
1024 diff -urN exim-4.63-orig/src/transport.c exim-4.63-dsn/src/transport.c
1025 --- exim-4.63-orig/src/transport.c 2006-07-31 15:19:48.000000000 +0100
1026 +++ exim-4.63-dsn/src/transport.c 2006-09-12 11:47:24.000000000 +0100
1027 @@ -1756,6 +1756,11 @@
1029 argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
1031 + #ifdef SUPPORT_DSN
1032 + /* Call with the dsn flag */
1033 + if (smtp_use_dsn) argv[i++] = US"-MCD";
1036 if (smtp_authenticated) argv[i++] = US"-MCA";
1039 diff -urN exim-4.63-orig/src/transports/smtp.c exim-4.63-dsn/src/transports/smtp.c
1040 --- exim-4.63-orig/src/transports/smtp.c 2006-07-31 15:19:48.000000000 +0100
1041 +++ exim-4.63-dsn/src/transports/smtp.c 2006-09-12 11:47:24.000000000 +0100
1042 @@ -194,6 +194,16 @@
1043 static uschar *smtp_command; /* Points to last cmd for error messages */
1044 static uschar *mail_command; /* Points to MAIL cmd for error messages */
1047 +/* some DSN flags for use later */
1049 +static int rf_list[] = {rf_notify_never, rf_notify_success,
1050 + rf_notify_failure, rf_notify_delay };
1052 +static uschar *rf_names[] = { "NEVER", "SUCCESS", "FAILURE", "DELAY" };
1057 /*************************************************
1058 * Setup entry point *
1059 @@ -1137,6 +1147,14 @@
1060 DEBUG(D_transport) debug_printf("%susing PIPELINING\n",
1061 smtp_use_pipelining? "" : "not ");
1063 + #ifdef SUPPORT_DSN
1064 + /* Note if the server supports DSN */
1065 + smtp_use_dsn = dsn &&
1066 + esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0,
1067 + PCRE_EOPT, NULL, 0) >= 0;
1068 + DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
1071 /* Note if the response to EHLO specifies support for the AUTH extension.
1072 If it has, check that this host is one we want to authenticate to, and do
1073 the business. The host name and address must be available when the
1074 @@ -1324,6 +1342,26 @@
1079 +/* Add any DSN flags to the mail command */
1083 + if (dsn_ret == dsn_ret_hdrs)
1085 + strcpy(p, " RET=HDRS");
1088 + else if (dsn_ret == dsn_ret_full)
1090 + strcpy(p, " RET=FULL");
1093 + if (dsn_envid != NULL)
1094 + string_format(p, sizeof(buffer) - (p-buffer), " ENVID=%s", dsn_envid);
1098 /* Add the authenticated sender address if present */
1100 if ((smtp_authenticated || ob->authenticated_sender_force) &&
1101 @@ -1386,18 +1424,66 @@
1105 + #ifdef SUPPORT_DSN
1106 + /* philb - set dsn_aware flag for this recipient */
1108 + addr->dsn_aware = string_copy("Y");
1110 + addr->dsn_aware = string_copy("N");
1113 if (addr->transport_return != PENDING_DEFER) continue;
1116 no_flush = smtp_use_pipelining && (!mua_wrapper || addr->next != NULL);
1118 + #ifdef SUPPORT_DSN
1119 + /* Add any DSN flags to the rcpt command and add to the sent string */
1126 + if ((addr->dsn_flags & rf_dsnflags) != 0)
1129 + BOOL first = TRUE;
1130 + strcpy(p, " NOTIFY=");
1132 + for (i = 0; i < 4; i++)
1134 + if ((addr->dsn_flags & rf_list[i]) != 0)
1136 + if (!first) *p++ = ',';
1138 + strcpy(p, rf_names[i]);
1144 + if (addr->dsn_orcpt != NULL)
1145 + string_format(p, sizeof(buffer) - (p-buffer), " ORCPT=%s",
1152 /* Now send the RCPT command, and process outstanding responses when
1153 necessary. After a timeout on RCPT, we just end the function, leaving the
1154 yield as OK, because this error can often mean that there is a problem with
1155 just one address, so we don't want to delay the host. */
1157 + #ifdef SUPPORT_DSN
1158 + count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
1159 + transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr, buffer);
1161 count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n",
1162 transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr);
1165 if (count < 0) goto SEND_FAILED;