1 diff -urN exim-4.64.org/README.DSN exim-4.64/README.DSN
2 --- exim-4.64.org/README.DSN 1970-01-01 01:00:00.000000000 +0100
3 +++ exim-4.64/README.DSN 2006-12-21 16:43:20.808508250 +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.64.org/src/config.h.defaults exim-4.64/src/config.h.defaults
110 --- exim-4.64.org/src/config.h.defaults 2006-12-20 10:46:04.000000000 +0100
111 +++ exim-4.64/src/config.h.defaults 2006-12-21 16:43:20.808508250 +0100
113 #define SUPPORT_MOVE_FROZEN_MESSAGES
117 #define SUPPORT_TRANSLATE_IP_ADDRESS
119 #define SYSLOG_LOG_PID
120 diff -urN exim-4.64.org/src/deliver.c exim-4.64/src/deliver.c
121 --- exim-4.64.org/src/deliver.c 2006-12-20 10:46:04.000000000 +0100
122 +++ exim-4.64/src/deliver.c 2006-12-21 16:43:20.812508500 +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 @@ -5981,6 +6010,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 @@ -6085,6 +6120,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.64.org/src/EDITME exim-4.64/src/EDITME
374 --- exim-4.64.org/src/EDITME 2006-12-20 10:46:04.000000000 +0100
375 +++ exim-4.64/src/EDITME 2006-12-21 16:43:20.812508500 +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.64.org/src/exim.c exim-4.64/src/exim.c
386 --- exim-4.64.org/src/exim.c 2006-12-20 10:46:04.000000000 +0100
387 +++ exim-4.64/src/exim.c 2006-12-21 16:43:20.816508750 +0100
389 #ifdef EXPERIMENTAL_DOMAINKEYS
390 fprintf(f, " Experimental_DomainKeys");
393 + fprintf(f, " C&W_DSN_1.2");
397 fprintf(f, "Lookups:");
398 @@ -2208,6 +2211,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.64.org/src/globals.c exim-4.64/src/globals.c
416 --- exim-4.64.org/src/globals.c 2006-12-20 10:46:04.000000000 +0100
417 +++ exim-4.64/src/globals.c 2006-12-21 16:43:20.816508750 +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.64.org/src/globals.h exim-4.64/src/globals.h
463 --- exim-4.64.org/src/globals.h 2006-12-20 10:46:04.000000000 +0100
464 +++ exim-4.64/src/globals.h 2006-12-21 16:43:20.816508750 +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.64.org/src/local_scan.h exim-4.64/src/local_scan.h
480 --- exim-4.64.org/src/local_scan.h 2006-12-20 10:46:04.000000000 +0100
481 +++ exim-4.64/src/local_scan.h 2006-12-21 16:43:20.816508750 +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.64.org/src/macros.h exim-4.64/src/macros.h
497 --- exim-4.64.org/src/macros.h 2006-12-20 10:46:04.000000000 +0100
498 +++ exim-4.64/src/macros.h 2006-12-21 16:43:20.816508750 +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 and host_all_ignored options. */
522 diff -urN exim-4.64.org/src/readconf.c exim-4.64/src/readconf.c
523 --- exim-4.64.org/src/readconf.c 2006-12-20 10:46:04.000000000 +0100
524 +++ exim-4.64/src/readconf.c 2006-12-21 16:43:20.820509000 +0100
526 { "dns_retrans", opt_time, &dns_retrans },
527 { "dns_retry", opt_int, &dns_retry },
528 { "dns_use_edns0", opt_int, &dns_use_edns0 },
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.64.org/src/receive.c exim-4.64/src/receive.c
536 --- exim-4.64.org/src/receive.c 2006-12-20 10:46:04.000000000 +0100
537 +++ exim-4.64/src/receive.c 2006-12-21 16:43:20.820509000 +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.64.org/src/route.c exim-4.64/src/route.c
548 --- exim-4.64.org/src/route.c 2006-12-20 10:46:04.000000000 +0100
549 +++ exim-4.64/src/route.c 2006-12-21 16:43:20.824509250 +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.64.org/src/smtp_in.c exim-4.64/src/smtp_in.c
588 --- exim-4.64.org/src/smtp_in.c 2006-12-20 10:46:04.000000000 +0100
589 +++ exim-4.64/src/smtp_in.c 2006-12-21 16:43:20.824509250 +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 @@ -2317,6 +2324,10 @@
609 + uschar *orcpt = NULL;
613 switch(smtp_read_command(TRUE))
615 @@ -2735,6 +2746,12 @@
616 s = string_cat(s, &size, &ptr, US"-8BITMIME\r\n", 11);
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 @@ -2946,6 +2963,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 @@ -3193,6 +3247,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 @@ -3300,6 +3437,24 @@
763 if (user_msg == NULL) smtp_printf("250 Accepted\r\n");
764 else smtp_user_msg(US"250", user_msg);
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.64.org/src/spool_in.c exim-4.64/src/spool_in.c
788 --- exim-4.64.org/src/spool_in.c 2006-12-20 10:46:04.000000000 +0100
789 +++ exim-4.64/src/spool_in.c 2006-12-21 16:47:28.415982750 +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. */
806 if (Ustrcmp(p, "eliver_firsttime") == 0)
807 deliver_firsttime = TRUE;
809 +#ifndef COMPILE_UTILITY
810 + /* Check if the dsn flags have been set in the header file */
811 + else if (Ustrncmp(p, "sn_ret", 8) == 0)
813 + dsn_ret = atoi(big_buffer + 8);
815 + else if (Ustrncmp(p, "sn_envid", 10) == 0)
817 + dsn_envid = string_copy(big_buffer + 11);
819 +#endif /* COMPILE_UTILITY */
830 + uschar *orcpt = NULL;
832 uschar *errors_to = NULL;
835 @@ -666,10 +690,19 @@
838 /* Handle current format Exim 4 spool files */
839 + /* Spool file is modified if DSN is supported
840 + Original was "address errors_to len(errors_to),pno
841 + New for DSN support is now:
842 + "address errors_to orcpt len(errors_to),len(orcpt),pno,dsn_flags */
848 + #ifndef COMPILE_UTILITY
849 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - Exim 4 standard format spoolfile\n");
850 + #endif /* COMPILE_UTILITY */
852 (void)sscanf(CS p+1, "%d", &flags);
854 if ((flags & 0x01) != 0) /* one_time data exists */
855 @@ -682,15 +715,82 @@
858 errors_to = string_copy(p);
862 + *(--p) = 0; /* Terminate address */
865 + else if (*p == '!') /* Handle Exim4 + DSN spool files */
868 + int temp_dsn_flags;
870 + #ifndef COMPILE_UTILITY
871 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - C&W DSN format spoolfile\n");
872 + #endif /* COMPILE_UTILITY */
874 + sscanf(CS p+1, "%d,%d", &flags, &temp_dsn_flags);
876 + if (((flags & 0x01) != 0) || (temp_dsn_flags > 0)) /* one_time data or dsn_flags exist */
881 + #ifndef COMPILE_UTILITY
882 + DEBUG(D_deliver) debug_printf("**** spool_in dsn_flags = 0\n");
883 + #endif /* COMPILE_UTILITY */
887 + while (isdigit(*(--p)) || *p == ',' || *p == '-');
888 + sscanf(CS p+1, "%d,%d,%d,%d", &len, &len_orcpt, &pno, &dsn_flags);
894 + orcpt = string_copy(p);
896 + *(--p) = 0; /* change the space to a NULL */
901 + errors_to = string_copy(p);
905 *(--p) = 0; /* Terminate address */
908 + #ifndef COMPILE_UTILITY
911 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - No additional fields\n");
913 + #endif /* COMPILE_UTILITY */
916 + #ifndef COMPILE_UTILITY
917 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
918 + big_buffer, errors_to, orcpt, dsn_flags);
919 + #endif /* COMPILE_UTILITY */
921 + #ifndef SUPPORT_DSN
922 + #ifndef COMPILE_UTILITY
923 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s|\n",
924 + big_buffer, errors_to);
925 + #endif /* COMPILE_UTILITY */
928 recipients_list[recipients_count].address = string_copy(big_buffer);
929 recipients_list[recipients_count].pno = pno;
930 recipients_list[recipients_count].errors_to = errors_to;
932 + recipients_list[recipients_count].orcpt = orcpt;
933 + recipients_list[recipients_count].dsn_flags = dsn_flags;
937 /* The remainder of the spool header file contains the headers for the message,
938 diff -urN exim-4.64.org/src/spool_out.c exim-4.64/src/spool_out.c
939 --- exim-4.64.org/src/spool_out.c 2006-12-20 10:46:04.000000000 +0100
940 +++ exim-4.64/src/spool_out.c 2006-12-21 16:43:20.828509500 +0100
942 if (tls_peerdn != NULL) fprintf(f, "-tls_peerdn %s\n", tls_peerdn);
946 +/* Write the dsn flags to the spool header file */
947 +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
948 +if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
949 +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret);
950 +if (dsn_ret != 0) fprintf(f, "-dsn_ret %d\n", dsn_ret);
954 /* To complete the envelope, write out the tree of non-recipients, followed by
955 the list of recipients. These won't be disjoint the first time, when no
956 checking has been done. If a recipient is a "one-time" alias, it is followed by
957 @@ -242,14 +251,36 @@
958 for (i = 0; i < recipients_count; i++)
960 recipient_item *r = recipients_list + i;
961 - if (r->pno < 0 && r->errors_to == NULL)
963 +DEBUG(D_deliver) debug_printf("DSN: Flags :%d\n", r->dsn_flags);
965 + if (r->pno < 0 && r->errors_to == NULL
967 + && r->dsn_flags == 0
970 fprintf(f, "%s\n", r->address);
973 uschar *errors_to = (r->errors_to == NULL)? US"" : r->errors_to;
975 + uschar *orcpt = (r->orcpt == NULL)? US"" : r->orcpt;
976 + fprintf(f, "%s %s %s %d,%d,%d,%d!1\n", r->address, errors_to, orcpt,
977 + Ustrlen(errors_to), Ustrlen(orcpt), r->pno, r->dsn_flags);
979 fprintf(f, "%s %s %d,%d#1\n", r->address, errors_to,
980 Ustrlen(errors_to), r->pno);
985 + DEBUG(D_deliver) debug_printf("DSN :**** SPOOL_OUT - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
986 + r->address, r->errors_to, r->orcpt, r->dsn_flags);
988 + #ifndef SUPPORT_DSN
989 + DEBUG(D_deliver) debug_printf("**** SPOOL_OUT - address: |%s| errorsto: |%s|\n",
990 + r->address, r->errors_to);
994 /* Put a blank line before the headers */
995 diff -urN exim-4.64.org/src/structs.h exim-4.64/src/structs.h
996 --- exim-4.64.org/src/structs.h 2006-12-20 10:46:04.000000000 +0100
997 +++ exim-4.64/src/structs.h 2006-12-21 16:43:20.828509500 +0100
999 BOOL verify_sender; /* Use this router when verifying a sender */
1000 BOOL uid_set; /* Flag to indicate uid is set */
1001 BOOL unseen; /* If TRUE carry on, even after success */
1004 + BOOL dsn_process; /* If TRUE, activate DSN for this router */
1006 int self_code; /* Encoded version of "self" */
1007 uid_t uid; /* Fixed uid value */
1008 gid_t gid; /* Fixed gid value */
1009 @@ -561,6 +563,12 @@
1010 uschar *peerdn; /* DN of server's certificate */
1013 + #ifdef SUPPORT_DSN
1014 + uschar *dsn_orcpt; /* DSN orcpt value */
1015 + int dsn_flags; /* DSN flags */
1016 + uschar *dsn_aware; /* DSN aware flag */
1019 uid_t uid; /* uid for transporting */
1020 gid_t gid; /* gid for transporting */
1022 diff -urN exim-4.64.org/src/transport.c exim-4.64/src/transport.c
1023 --- exim-4.64.org/src/transport.c 2006-12-20 10:46:04.000000000 +0100
1024 +++ exim-4.64/src/transport.c 2006-12-21 16:43:20.832509750 +0100
1025 @@ -1786,6 +1786,11 @@
1027 argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
1029 + #ifdef SUPPORT_DSN
1030 + /* Call with the dsn flag */
1031 + if (smtp_use_dsn) argv[i++] = US"-MCD";
1034 if (smtp_authenticated) argv[i++] = US"-MCA";
1037 diff -urN exim-4.64.org/src/transports/smtp.c exim-4.64/src/transports/smtp.c
1038 --- exim-4.64.org/src/transports/smtp.c 2006-12-20 10:46:04.000000000 +0100
1039 +++ exim-4.64/src/transports/smtp.c 2006-12-21 16:43:20.832509750 +0100
1040 @@ -191,6 +191,16 @@
1045 +/* some DSN flags for use later */
1047 +static int rf_list[] = {rf_notify_never, rf_notify_success,
1048 + rf_notify_failure, rf_notify_delay };
1050 +static uschar *rf_names[] = { "NEVER", "SUCCESS", "FAILURE", "DELAY" };
1057 @@ -1152,6 +1162,14 @@
1058 DEBUG(D_transport) debug_printf("%susing PIPELINING\n",
1059 smtp_use_pipelining? "" : "not ");
1061 + #ifdef SUPPORT_DSN
1062 + /* Note if the server supports DSN */
1063 + smtp_use_dsn = dsn &&
1064 + esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0,
1065 + PCRE_EOPT, NULL, 0) >= 0;
1066 + DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
1069 /* Note if the response to EHLO specifies support for the AUTH extension.
1070 If it has, check that this host is one we want to authenticate to, and do
1071 the business. The host name and address must be available when the
1072 @@ -1339,6 +1357,26 @@
1077 +/* Add any DSN flags to the mail command */
1081 + if (dsn_ret == dsn_ret_hdrs)
1083 + strcpy(p, " RET=HDRS");
1086 + else if (dsn_ret == dsn_ret_full)
1088 + strcpy(p, " RET=FULL");
1091 + if (dsn_envid != NULL)
1092 + string_format(p, sizeof(buffer) - (p-buffer), " ENVID=%s", dsn_envid);
1096 /* Add the authenticated sender address if present */
1098 if ((smtp_authenticated || ob->authenticated_sender_force) &&
1099 @@ -1401,18 +1439,66 @@
1103 + #ifdef SUPPORT_DSN
1104 + /* philb - set dsn_aware flag for this recipient */
1106 + addr->dsn_aware = string_copy("Y");
1108 + addr->dsn_aware = string_copy("N");
1111 if (addr->transport_return != PENDING_DEFER) continue;
1114 no_flush = smtp_use_pipelining && (!mua_wrapper || addr->next != NULL);
1116 + #ifdef SUPPORT_DSN
1117 + /* Add any DSN flags to the rcpt command and add to the sent string */
1124 + if ((addr->dsn_flags & rf_dsnflags) != 0)
1127 + BOOL first = TRUE;
1128 + strcpy(p, " NOTIFY=");
1130 + for (i = 0; i < 4; i++)
1132 + if ((addr->dsn_flags & rf_list[i]) != 0)
1134 + if (!first) *p++ = ',';
1136 + strcpy(p, rf_names[i]);
1142 + if (addr->dsn_orcpt != NULL)
1143 + string_format(p, sizeof(buffer) - (p-buffer), " ORCPT=%s",
1150 /* Now send the RCPT command, and process outstanding responses when
1151 necessary. After a timeout on RCPT, we just end the function, leaving the
1152 yield as OK, because this error can often mean that there is a problem with
1153 just one address, so we don't want to delay the host. */
1155 + #ifdef SUPPORT_DSN
1156 + count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
1157 + transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr, buffer);
1159 count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n",
1160 transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr);
1163 if (count < 0) goto SEND_FAILED;