Gentoo Archives: gentoo-commits

From: "Fabian Groffen (grobian)" <grobian@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] gentoo-x86 commit in mail-mta/exim/files: exim_482_dsn_1_3.patch
Date: Sun, 27 Oct 2013 20:56:30
Message-Id: 20131027205622.731D020047@flycatcher.gentoo.org
1 grobian 13/10/27 20:56:22
2
3 Added: exim_482_dsn_1_3.patch
4 Log:
5 Add dsn patch that applies, but needs testing, bug #489242
6
7 (Portage version: 2.2.7-prefix/cvs/Darwin i386, signed Manifest commit with key 0x5F75F607C5C74E89)
8
9 Revision Changes Path
10 1.1 mail-mta/exim/files/exim_482_dsn_1_3.patch
11
12 file : http://sources.gentoo.org/viewvc.cgi/gentoo-x86/mail-mta/exim/files/exim_482_dsn_1_3.patch?rev=1.1&view=markup
13 plain: http://sources.gentoo.org/viewvc.cgi/gentoo-x86/mail-mta/exim/files/exim_482_dsn_1_3.patch?rev=1.1&content-type=text/plain
14
15 Index: exim_482_dsn_1_3.patch
16 ===================================================================
17 Modified for 4.82 by Gentoo -- not the official patch from
18 http://sourceforge.net/projects/eximdsn/
19
20 diff -Naur exim-4.82_RC5.orig/README.DSN exim-4.82_RC5/README.DSN
21 --- exim-4.82_RC5.orig/README.DSN 1970-01-01 01:00:00.000000000 +0100
22 +++ exim-4.82_RC5/README.DSN 2013-10-27 21:47:32.000000000 +0100
23 @@ -0,0 +1,118 @@
24 +Exim DSN Patch (4.76)
25 +---------------------
26 +
27 +This patch is free software; you can redistribute it and/or modify
28 +it under the terms of the GNU General Public License as published by
29 +the Free Software Foundation; either version 2 of the License, or
30 +(at your option) any later version.
31 +
32 +This patch is distributed in the hope that it will be useful,
33 +but WITHOUT ANY WARRANTY; without even the implied warranty of
34 +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 +GNU General Public License for more details.
36 +
37 +You should have received a copy of the GNU General Public License
38 +along with this patch; if not, write to the Free Software
39 +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
40 +
41 +Install
42 +-------
43 +cd into the source tree for a vanilla exim
44 +
45 +patch -p1 </path/to/patch/file.patch
46 +
47 +Example :-
48 +[root@linuxbuild exim-4.72-test]# patch -p1 <../exim.dsn.patch-472
49 +
50 +Expected Output :-
51 +patching file README.DSN
52 +patching file src/config.h.defaults
53 +patching file src/deliver.c
54 +patching file src/exim.c
55 +patching file src/exim.h
56 +patching file src/globals.c
57 +patching file src/globals.h
58 +patching file src/local_scan.h
59 +patching file src/macros.h
60 +patching file src/readconf.c
61 +patching file src/route.c
62 +patching file src/smtp_in.c
63 +patching file src/spool_in.c
64 +patching file src/spool_out.c
65 +patching file src/structs.h
66 +patching file src/transport.c
67 +patching file src/transports/smtp.c
68 +
69 +
70 +This patch can be included / excluded from the compilation by use of the #define SUPPORT_DSN
71 +which gets added into src/config.h.defaults & src/EDITME by the patch.
72 +
73 +Use
74 +---
75 +
76 +The facility (once compiled in) can be turned on for a particular router via the
77 +dsn_process directive Eg :-
78 +
79 +dest_delivery_int:
80 + driver = manualroute
81 + domains = +relay_to_domains
82 + condition = ${if eq {${lc:$sender_address_domain}}\
83 + {domain.com}\
84 + {yes}{no}\
85 + }
86 + dsn_process
87 + hide route_data = ${lc:${extract{mailHost}{$address_data}{$value}{}}}
88 + transport = remote_smtp
89 +
90 +Exim will produce 1 of 2 DSN's back to the originator, or pass on the DSN request.
91 +The 2 DSN's will either contain (relayed via non "Remote SMTP" router) or
92 +(relayed to non-DSN-aware mailer) depending on if the delivery was VIA an SMTP
93 +transport or not.
94 +
95 +
96 +Credits
97 +-------
98 +
99 +The original work for the patch was done by Philip Hazel in Exim 3
100 +
101 +The extract was taken and re-applied to Exim 4 by the following :-
102 +Phil Bingham (phil.bingham@××××××××.net)
103 +Steve Falla (steve.falla@××××××××.net)
104 +Ray Edah (ray.edah@××××××××.net)
105 +Andrew Johnson (andrew.johnson@××××××××.net)
106 +Adrian Hungate (adrian.hungate@××××××××.net)
107 +
108 +Now Primarily maintained by :-
109 +Andrew Johnson (andrew.johnson@××××××××.net)
110 +
111 +Contributions
112 +-------------
113 +Andrey J. Melnikoff (TEMHOTA) (temnota@×××.ru)
114 +
115 +
116 +ChangeLog
117 +---------
118 +
119 +14-Apr-2006 : Changed subject to "Delivery Status Notification"
120 +
121 +17-May-2006 : debug_printf in spool-in.c were not wrapped with #ifndef COMPILE_UTILITY
122 + thanks to Andrey J. Melnikoff for this information
123 +
124 +12-Sep-2006 : Now supports Exim 4.63
125 +
126 +12-Sep-2006 : src/EDITME did not include the #define SUPPORT_DSN as stated
127 + in the documentation, this has now been corrected
128 + thanks to Robert Kehl for this information
129 +
130 +28-Jul-2008 : New version for exim 4.69 released.
131 +
132 +02-Jul-2010 : New version for exim 4.72 released.
133 +
134 +20-May-2011 : New version for exim 4.76 released.
135 +
136 +
137 +Support for this patch (limited though it is) will only be provided through the SourceForge
138 +project page (http://sourceforge.net/projects/eximdsn/)
139 +
140 +--
141 +Andrew Johnson Cable & Wireless
142 diff -Naur exim-4.82_RC5.orig/src/config.h.defaults exim-4.82_RC5/src/config.h.defaults
143 --- exim-4.82_RC5.orig/src/config.h.defaults 2013-10-27 21:46:25.000000000 +0100
144 +++ exim-4.82_RC5/src/config.h.defaults 2013-10-27 21:47:32.000000000 +0100
145 @@ -136,6 +136,7 @@
146 #define SUPPORT_MOVE_FROZEN_MESSAGES
147 #define SUPPORT_PAM
148 #define SUPPORT_TLS
149 +#define SUPPORT_DSN
150 #define SUPPORT_TRANSLATE_IP_ADDRESS
151
152 #define SYSLOG_LOG_PID
153 diff -Naur exim-4.82_RC5.orig/src/deliver.c exim-4.82_RC5/src/deliver.c
154 --- exim-4.82_RC5.orig/src/deliver.c 2013-10-27 21:46:25.000000000 +0100
155 +++ exim-4.82_RC5/src/deliver.c 2013-10-27 21:47:32.000000000 +0100
156 @@ -63,6 +63,9 @@
157 static address_item *addr_remote = NULL;
158 static address_item *addr_route = NULL;
159 static address_item *addr_succeed = NULL;
160 +#ifdef SUPPORT_DSN
161 +static address_item *addr_dsntmp = NULL;
162 +#endif
163
164 static FILE *message_log = NULL;
165 static BOOL update_spool;
166 @@ -2966,6 +2969,15 @@
167 addr->flags |= af_prdr_used; break;
168 #endif
169
170 + #ifdef SUPPORT_DSN
171 + case 'D':
172 + if (addr == NULL) break;
173 + addr->dsn_aware = (*ptr)? string_copy(ptr) : string_copy(" ");
174 + while (*ptr++);
175 + DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %s\n", addr->dsn_aware);
176 + break;
177 + #endif
178 +
179 case 'A':
180 if (addr == NULL)
181 {
182 @@ -4074,6 +4086,15 @@
183 if (addr->flags & af_prdr_used) rmt_dlv_checked_write(fd, "P", 1);
184 #endif
185
186 + #ifdef SUPPORT_DSN
187 + if (addr->dsn_aware == NULL)
188 + addr->dsn_aware = string_copy(" ");
189 + DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %s\n", addr->dsn_aware);
190 + sprintf(big_buffer, "D%s", addr->dsn_aware);
191 + DEBUG(D_deliver) debug_printf("DSN write: big_buffer = %s (%d)\n", big_buffer, strlen(big_buffer)+1);
192 + write(fd, big_buffer, strlen(big_buffer)+1);
193 + #endif
194 +
195 /* Retry information: for most success cases this will be null. */
196
197 for (r = addr->retries; r != NULL; r = r->next)
198 @@ -5219,6 +5240,14 @@
199 if (r->pno >= 0)
200 new->onetime_parent = recipients_list[r->pno].address;
201
202 + #ifdef SUPPORT_DSN
203 + /* If DSN support is enabled, set the dsn flags and the original receipt
204 + to be passed on to other DSN enabled MTAs */
205 + new->dsn_flags = r->dsn_flags & rf_dsnflags;
206 + new->dsn_orcpt = r->orcpt;
207 + debug_printf("DSN (deliver): orcpt: %s flags: %d\n", new->dsn_orcpt, new->dsn_flags);
208 + #endif
209 +
210 switch (process_recipients)
211 {
212 /* RECIP_DEFER is set when a system filter freezes a message. */
213 @@ -6163,6 +6192,12 @@
214 regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
215 #endif
216
217 + #ifdef SUPPORT_DSN
218 + /* Set the regex to check for DSN support on remote MTA */
219 + if (regex_DSN == NULL) regex_DSN =
220 + regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
221 + #endif
222 +
223 /* Now sort the addresses if required, and do the deliveries. The yield of
224 do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
225 cannot be delivered in one transaction. */
226 @@ -6267,6 +6302,179 @@
227
228 else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed);
229
230 +#ifdef SUPPORT_DSN
231 +/* ********** philb - Send DSN for successful messages */
232 +
233 +addr_dsntmp = addr_succeed;
234 +
235 +while(addr_dsntmp != NULL)
236 +{
237 + BOOL dsn_sendmessage = FALSE;
238 + uschar dsnmsgbuf[4096];
239 +
240 + DEBUG(D_deliver)
241 + debug_printf("DSN: processing router : %s\n", addr_dsntmp->router->name);
242 +
243 + DEBUG(D_deliver)
244 + debug_printf("DSN: processing successful delivery address: %s\n", addr_dsntmp->address);
245 +
246 + if (testflag(addr_dsntmp, af_ignore_error))
247 + {
248 + DEBUG(D_deliver)
249 + debug_printf("DSN: Ignore error for: %s\n", addr_dsntmp->address);
250 + }
251 + else
252 + {
253 + DEBUG(D_deliver) debug_printf("DSN: Checking Flag\n");
254 + if (addr_dsntmp->dsn_aware == NULL) {
255 + DEBUG(D_deliver) debug_printf("DSN: dsn_aware was NULL, setting to space at %s %d\n", __FILE__, __LINE__);
256 + addr_dsntmp->dsn_aware = string_copy(" ");
257 + }
258 + DEBUG(D_deliver) debug_printf("DSN: Sender_address: %s\n", sender_address);
259 + DEBUG(D_deliver) debug_printf("DSN: orcpt: %s flags: %d\n", addr_dsntmp->dsn_orcpt, addr_dsntmp->dsn_flags);
260 + DEBUG(D_deliver) debug_printf("DSN: envid: %s ret: %d\n", dsn_envid, dsn_ret);
261 + DEBUG(D_deliver) debug_printf("DSN: Remote SMTP server supports DSN: %s\n", addr_dsntmp->dsn_aware);
262 +
263 + /* Process the flags */
264 + if((addr_dsntmp->dsn_flags & rf_dsnflags) != 0)
265 + {
266 + /* We've got at least one flag set */
267 +
268 + /* set flag so we don't send bounces */
269 + setflag(addr_dsntmp, af_ignore_error);
270 +
271 + if((addr_dsntmp->dsn_flags & rf_notify_never) != 0)
272 + {
273 + DEBUG(D_deliver) debug_printf("DSN: NEVER FLAG\n");
274 +
275 + /* nothing to do here */
276 + }
277 +
278 + if((addr_dsntmp->dsn_flags & rf_notify_success) != 0)
279 + {
280 + DEBUG(D_deliver) debug_printf("DSN: SUCCESS FLAG\n");
281 +
282 + dsn_sendmessage = TRUE;
283 + }
284 +
285 + if((addr_dsntmp->dsn_flags & rf_notify_failure) != 0)
286 + {
287 + DEBUG(D_deliver) debug_printf("DSN: FAILURE FLAG\n");
288 +
289 + /* allow bounce messages */
290 + clearflag(addr_dsntmp, af_ignore_error);
291 + }
292 +
293 + if((addr_dsntmp->dsn_flags & rf_notify_delay) != 0)
294 + {
295 + DEBUG(D_deliver) debug_printf("DSN: DELAY FLAG\n");
296 +
297 + /* hmm, what to do here? */
298 + }
299 + }
300 +
301 + if ((addr_dsntmp->dsn_aware != 0) && (addr_dsntmp->dsn_aware[0] != 'Y') && (dsn_sendmessage == TRUE) && (addr_dsntmp->router->dsn_process == TRUE))
302 + {
303 + pid_t pid;
304 + int fd;
305 +
306 + /* remote MTA does not support DSN, so we need to send message */
307 +
308 + /* create exim process to send message */
309 + pid = child_open_exim(&fd);
310 +
311 + DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %d\n", pid);
312 +
313 + if (pid < 0) /* Creation of child failed */
314 + {
315 + log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to "
316 + "create child process to send failure message: %s", getpid(),
317 + getppid(), strerror(errno));
318 +
319 + DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n");
320 +
321 + }
322 + else /* Creation of child succeeded */
323 + {
324 + FILE *f = fdopen(fd, "wb");
325 + int topt = topt_add_return_path;
326 + uschar boundaryStr[64];
327 +
328 + DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address);
329 +
330 + /* build unique id for MIME boundary */
331 + snprintf(boundaryStr, 63, "%d-cwdsn-%d", pid, rand());
332 + DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr);
333 +
334 + /* if the sender doesn't want the whole message returned, don't send the body */
335 + if (dsn_ret != dsn_ret_full) topt |= topt_no_body;
336 +
337 + if (errors_reply_to != NULL) fprintf(f,"Reply-To: %s\n", errors_reply_to);
338 +
339 + fprintf(f,"Auto-Submitted: auto-generated\n");
340 + fprintf(f,"From: Mail Delivery System <Mailer-Daemon@%s>\n", qualify_domain_sender);
341 + fprintf(f,"To: %s\n", sender_address);
342 + fprintf(f,"Subject: Delivery Status Notification\n");
343 + fprintf(f,"Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n", boundaryStr);
344 + fprintf(f,"MIME-Version: 1.0\n\n");
345 +
346 + fprintf(f,"--%s\n", boundaryStr);
347 + fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n");
348 +
349 + fprintf(f,"This message was created automatically by mail delivery software.\n");
350 + fprintf(f," ----- The following addresses had successful delivery notifications -----\n");
351 +/* AH: added specific message for non "Remote SMTP" situations */
352 + if (addr_dsntmp->dsn_aware[0] == 'N') {
353 + fprintf(f,"<%s> (relayed to non-DSN-aware mailer)\n\n", addr_dsntmp->address);
354 + } else {
355 + fprintf(f,"<%s> (relayed via non \"Remote SMTP\" router)\n\n", addr_dsntmp->address);
356 + }
357 +
358 + fprintf(f,"--%s\n", boundaryStr);
359 + fprintf(f,"Content-type: message/delivery-status\n\n");
360 +
361 + if (dsn_envid) { /* Test for NULL added by GC */
362 + fprintf(f,"Original-Envelope-Id: %s\n", dsn_envid);
363 + }
364 + fprintf(f,"Reporting-MTA: dns; %s\n", qualify_domain_sender);
365 + if (addr_dsntmp->dsn_orcpt) { /* Test for NULL added by GC */
366 + fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt);
367 + }
368 + fprintf(f,"Action: delivered\n\n");
369 +
370 + fprintf(f,"--%s\n", boundaryStr);
371 + fprintf(f,"Content-type: message/rfc822\n\n");
372 +
373 + fflush(f);
374 + transport_filter_argv = NULL; /* Just in case */
375 + return_path = sender_address; /* In case not previously set */
376 +
377 + /* Write the original email out */
378 + transport_write_message(NULL, fileno(f), topt, 2048, NULL, NULL, NULL, NULL, NULL, 0);
379 + fflush(f);
380 +
381 + fprintf(f,"\n");
382 + fprintf(f,"--%s--\n", boundaryStr);
383 +
384 + fflush(f);
385 + fclose(f);
386 + rc = child_close(pid, 0); /* Waits for child to close, no timeout */
387 + }
388 + }
389 + else
390 + { if (addr_dsntmp->router->dsn_process == TRUE)
391 + DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message ***\n");
392 + if (addr_dsntmp->router->dsn_process == FALSE)
393 + DEBUG(D_deliver) debug_printf("DSN: *** NOT SENDING DSN SUCCESS Message (gagged) ***\n");
394 + }
395 + }
396 +
397 + addr_dsntmp = addr_dsntmp->next;
398 +}
399 +
400 +/* ********** philb - end of mod */
401 +#endif
402 +
403 /* If any addresses failed, we must send a message to somebody, unless
404 af_ignore_error is set, in which case no action is taken. It is possible for
405 several messages to get sent if there are addresses with different
406 diff -Naur exim-4.82_RC5.orig/src/EDITME exim-4.82_RC5/src/EDITME
407 --- exim-4.82_RC5.orig/src/EDITME 2013-10-27 21:46:25.000000000 +0100
408 +++ exim-4.82_RC5/src/EDITME 2013-10-27 21:47:32.000000000 +0100
409 @@ -192,6 +192,8 @@
410 # least one type of lookup. You should consider whether you want to build
411 # the Exim monitor or not.
412
413 +# Support DSN
414 +SUPPORT_DSN=yes
415
416 #------------------------------------------------------------------------------
417 # These settings determine which individual router drivers are included in the
418 diff -Naur exim-4.82_RC5.orig/src/exim.c exim-4.82_RC5/src/exim.c
419 --- exim-4.82_RC5.orig/src/exim.c 2013-10-27 21:46:25.000000000 +0100
420 +++ exim-4.82_RC5/src/exim.c 2013-10-27 21:47:32.000000000 +0100
421 @@ -831,6 +831,9 @@
422 #ifdef EXPERIMENTAL_REDIS
423 fprintf(f, " Experimental_Redis");
424 #endif
425 +#ifdef SUPPORT_DSN
426 + fprintf(f, " C&W_DSN_1.3");
427 +#endif
428 fprintf(f, "\n");
429
430 fprintf(f, "Lookups (built-in):");
431 @@ -2653,6 +2656,16 @@
432 break;
433 }
434
435 + #ifdef SUPPORT_DSN
436 + /* -MCD: set the smtp_use_dsn flag; this indicates that the host
437 + that exim is connected to supports the esmtp extension DSN */
438 + else if (strcmp(argrest, "CD") == 0)
439 + {
440 + smtp_use_dsn = TRUE;
441 + break;
442 + }
443 + #endif
444 +
445 /* -MCP: set the smtp_use_pipelining flag; this is useful only when
446 it preceded -MC (see above) */
447
448 diff -Naur exim-4.82_RC5.orig/src/globals.c exim-4.82_RC5/src/globals.c
449 --- exim-4.82_RC5.orig/src/globals.c 2013-10-27 21:46:25.000000000 +0100
450 +++ exim-4.82_RC5/src/globals.c 2013-10-27 21:47:32.000000000 +0100
451 @@ -124,6 +124,13 @@
452 uschar *local_scan_path = NULL;
453 #endif
454
455 +#ifdef SUPPORT_DSN
456 +BOOL dsn = TRUE;
457 +uschar *dsn_envid = NULL;
458 +int dsn_ret = 0;
459 +const pcre *regex_DSN = NULL;
460 +BOOL smtp_use_dsn = FALSE;
461 +#endif
462
463 #ifdef SUPPORT_TLS
464 BOOL gnutls_compat_mode = FALSE;
465 @@ -341,6 +348,11 @@
466 NULL, /* authenticator */
467 NULL, /* auth_id */
468 NULL, /* auth_sndr */
469 + #ifdef SUPPORT_DSN
470 + NULL, /* dsn_orcpt */
471 + 0, /* dsn_flags */
472 + NULL, /* dsn_aware */
473 + #endif
474 (uid_t)(-1), /* uid */
475 (gid_t)(-1), /* gid */
476 0, /* flags */
477 @@ -1096,6 +1108,9 @@
478 TRUE, /* verify_sender */
479 FALSE, /* uid_set */
480 FALSE, /* unseen */
481 +#ifdef SUPPORT_DSN
482 + FALSE, /* dsn_process */
483 +#endif
484
485 self_freeze, /* self_code */
486 (uid_t)(-1), /* uid */
487 @@ -1105,6 +1120,7 @@
488 NULL, /* transport instance */
489 NULL, /* pass_router */
490 NULL /* redirect_router */
491 +
492 };
493
494 uschar *router_name = NULL;
495 diff -Naur exim-4.82_RC5.orig/src/globals.h exim-4.82_RC5/src/globals.h
496 --- exim-4.82_RC5.orig/src/globals.h 2013-10-27 21:46:25.000000000 +0100
497 +++ exim-4.82_RC5/src/globals.h 2013-10-27 21:47:32.000000000 +0100
498 @@ -130,6 +130,13 @@
499 extern int (*receive_ferror)(void);
500 extern BOOL (*receive_smtp_buffered)(void);
501
502 +#ifdef SUPPORT_DSN
503 +extern BOOL dsn; /* FALSE if DSN not to be used */
504 +extern uschar *dsn_envid; /* DSN envid string */
505 +extern int dsn_ret; /* DSN ret type*/
506 +extern const pcre *regex_DSN; /* For recognizing DSN settings */
507 +extern BOOL smtp_use_dsn; /* Global for passed connections */
508 +#endif
509
510 /* For clearing, saving, restoring address expansion variables. We have to have
511 the size of this vector set explicitly, because it is referenced from more than
512 diff -Naur exim-4.82_RC5.orig/src/local_scan.h exim-4.82_RC5/src/local_scan.h
513 --- exim-4.82_RC5.orig/src/local_scan.h 2013-10-27 21:46:25.000000000 +0100
514 +++ exim-4.82_RC5/src/local_scan.h 2013-10-27 21:47:32.000000000 +0100
515 @@ -124,9 +124,13 @@
516 field is always NULL except for one_time aliases that had errors_to on the
517 routers that generated them. */
518
519 +/* Added the dsn attributes orcpt and dsn_flags for DSN support*/
520 +
521 typedef struct recipient_item {
522 uschar *address; /* the recipient address */
523 int pno; /* parent number for "one_time" alias, or -1 */
524 + uschar *orcpt; /* DSN orcpt */
525 + int dsn_flags; /* DSN flags */
526 uschar *errors_to; /* the errors_to address or NULL */
527 #ifdef EXPERIMENTAL_BRIGHTMAIL
528 uschar *bmi_optin;
529 diff -Naur exim-4.82_RC5.orig/src/macros.h exim-4.82_RC5/src/macros.h
530 --- exim-4.82_RC5.orig/src/macros.h 2013-10-27 21:46:25.000000000 +0100
531 +++ exim-4.82_RC5/src/macros.h 2013-10-27 21:47:32.000000000 +0100
532 @@ -778,6 +778,22 @@
533 #define topt_no_body 0x040 /* Omit body */
534 #define topt_escape_headers 0x080 /* Apply escape check to headers */
535
536 + /* Flags for recipient_block, used in DSN support */
537 +
538 + #define rf_onetime 0x01 /* A one-time alias */
539 + #define rf_notify_never 0x02 /* NOTIFY= settings */
540 + #define rf_notify_success 0x04
541 + #define rf_notify_failure 0x08
542 + #define rf_notify_delay 0x10
543 +
544 + #define rf_dsnflags (rf_notify_never | rf_notify_success | \
545 + rf_notify_failure | rf_notify_delay)
546 +
547 + /* DSN RET types */
548 +
549 + #define dsn_ret_full 1
550 + #define dsn_ret_hdrs 2
551 +
552 /* Codes for the host_find_failed and host_all_ignored options. */
553
554 #define hff_freeze 0
555 diff -Naur exim-4.82_RC5.orig/src/readconf.c exim-4.82_RC5/src/readconf.c
556 --- exim-4.82_RC5.orig/src/readconf.c 2013-10-27 21:46:25.000000000 +0100
557 +++ exim-4.82_RC5/src/readconf.c 2013-10-27 21:49:15.000000000 +0100
558 @@ -229,6 +229,9 @@
559 /* This option is now a no-op, retained for compability */
560 { "drop_cr", opt_bool, &drop_cr },
561 /*********************************************************/
562 +#ifdef SUPPORT_DSN
563 + { "dsn", opt_bool, &dsn },
564 +#endif
565 { "dsn_from", opt_stringptr, &dsn_from },
566 { "envelope_to_remove", opt_bool, &envelope_to_remove },
567 { "errors_copy", opt_stringptr, &errors_copy },
568 diff -Naur exim-4.82_RC5.orig/src/receive.c exim-4.82_RC5/src/receive.c
569 --- exim-4.82_RC5.orig/src/receive.c 2013-10-27 21:46:25.000000000 +0100
570 +++ exim-4.82_RC5/src/receive.c 2013-10-27 21:47:32.000000000 +0100
571 @@ -490,6 +490,8 @@
572 memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item));
573 }
574
575 +/* memset added by GC to blank dsn records, etc. */
576 +memset(&recipients_list[recipients_count], 0, sizeof(recipient_item));
577 recipients_list[recipients_count].address = recipient;
578 recipients_list[recipients_count].pno = pno;
579 #ifdef EXPERIMENTAL_BRIGHTMAIL
580 diff -Naur exim-4.82_RC5.orig/src/route.c exim-4.82_RC5/src/route.c
581 --- exim-4.82_RC5.orig/src/route.c 2013-10-27 21:46:25.000000000 +0100
582 +++ exim-4.82_RC5/src/route.c 2013-10-27 21:47:32.000000000 +0100
583 @@ -58,6 +58,10 @@
584 (void *)offsetof(router_instance, domains) },
585 { "driver", opt_stringptr|opt_public,
586 (void *)offsetof(router_instance, driver_name) },
587 + #ifdef SUPPORT_DSN
588 + { "dsn_process", opt_bool|opt_public,
589 + (void *)offsetof(router_instance, dsn_process) },
590 + #endif
591 { "errors_to", opt_stringptr|opt_public,
592 (void *)(offsetof(router_instance, errors_to)) },
593 { "expn", opt_bool|opt_public,
594 @@ -270,6 +274,13 @@
595
596 if (r->pass_router_name != NULL)
597 set_router(r, r->pass_router_name, &(r->pass_router), TRUE);
598 +
599 + #ifdef SUPPORT_DSN
600 + if (r->dsn_process == FALSE)
601 + DEBUG(D_route) debug_printf("%s router skipping DSN - add dsn_process to router\n", r->name);
602 + if (r->dsn_process == TRUE)
603 + DEBUG(D_route) debug_printf("%s router performing DSN \n", r->name);
604 + #endif
605 }
606 }
607
608 @@ -1412,7 +1423,10 @@
609
610 copyflag(new, addr, af_propagate);
611 new->p.address_data = addr->p.address_data;
612 -
613 +#ifdef SUPPORT_DSN
614 + new->dsn_flags = addr->dsn_flags;
615 + new->dsn_orcpt = addr->dsn_orcpt;
616 +#endif
617
618 /* As it has turned out, we haven't set headers_add or headers_remove for the
619 * clone. Thinking about it, it isn't entirely clear whether they should be
620 diff -Naur exim-4.82_RC5.orig/src/smtp_in.c exim-4.82_RC5/src/smtp_in.c
621 --- exim-4.82_RC5.orig/src/smtp_in.c 2013-10-27 21:46:25.000000000 +0100
622 +++ exim-4.82_RC5/src/smtp_in.c 2013-10-27 21:47:32.000000000 +0100
623 @@ -213,6 +213,9 @@
624 #ifdef EXPERIMENTAL_PRDR
625 ENV_MAIL_OPT_PRDR,
626 #endif
627 +#ifdef SUPPORT_DSN
628 + ENV_MAIL_OPT_RET, ENV_MAIL_OPT_ENVID,
629 +#endif
630 ENV_MAIL_OPT_NULL
631 };
632 typedef struct {
633 @@ -228,6 +231,10 @@
634 #ifdef EXPERIMENTAL_PRDR
635 { US"PRDR", ENV_MAIL_OPT_PRDR, FALSE },
636 #endif
637 +#ifdef SUPPORT_DSN
638 + { US"RET", ENV_MAIL_OPT_RET, FALSE },
639 + { US"ENVID", ENV_MAIL_OPT_ENVID, FALSE },
640 +#endif
641 { US"NULL", ENV_MAIL_OPT_NULL, FALSE }
642 };
643
644 @@ -1073,6 +1080,13 @@
645 sender_verified_list = NULL; /* No senders verified */
646 memset(sender_address_cache, 0, sizeof(sender_address_cache));
647 memset(sender_domain_cache, 0, sizeof(sender_domain_cache));
648 +
649 +#ifdef SUPPORT_DSN
650 +/* Reset the DSN flags */
651 +dsn_ret = 0;
652 +dsn_envid = NULL;
653 +#endif
654 +
655 authenticated_sender = NULL;
656 #ifdef EXPERIMENTAL_BRIGHTMAIL
657 bmi_run = 0;
658 @@ -2679,6 +2693,10 @@
659 int ptr, size, rc;
660 int c, i;
661 auth_instance *au;
662 +#ifdef SUPPORT_DSN
663 + uschar *orcpt = NULL;
664 + int flags;
665 +#endif
666
667 switch(smtp_read_command(TRUE))
668 {
669 @@ -3106,6 +3124,12 @@
670 s = string_cat(s, &size, &ptr, US"-8BITMIME\r\n", 11);
671 }
672
673 + #ifdef SUPPORT_DSN
674 + /* Advertise DSN support if configured to do so. */
675 + if (dsn)
676 + s = string_cat(s, &size, &ptr, US"250-DSN\r\n", 9);
677 + #endif
678 +
679 /* Advertise ETRN if there's an ACL checking whether a host is
680 permitted to issue it; a check is made when any host actually tries. */
681
682 @@ -3360,6 +3384,42 @@
683 arg_error = TRUE;
684 break;
685
686 +#ifdef SUPPORT_DSN
687 +
688 + /* Handle the two DSN options, but only if configured to do so
689 + * (which will have caused "DSN" to be given in the EHLO
690 + * response). The code itself is included only if configured in
691 + * at build time. */
692 +
693 + case ENV_MAIL_OPT_RET:
694 + /* Check if RET has already been set */
695 + if (dsn_ret > 0) {
696 + synprot_error(L_smtp_syntax_error, 501, NULL,
697 + US"RET can be specified once only");
698 + goto COMMAND_LOOP;
699 + }
700 + dsn_ret = (strcmpic(value, US"HDRS") == 0)? dsn_ret_hdrs :
701 + (strcmpic(value, US"FULL") == 0)? dsn_ret_full : 0;
702 + DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret);
703 + /* Check for invalid invalid value, and exit with error */
704 + if (dsn_ret == 0) {
705 + synprot_error(L_smtp_syntax_error, 501, NULL,
706 + US"Value for RET is invalid");
707 + goto COMMAND_LOOP;
708 + }
709 + break;
710 + case ENV_MAIL_OPT_ENVID:
711 + /* Check if the dsn envid has been already set */
712 + if (dsn_envid != NULL) {
713 + synprot_error(L_smtp_syntax_error, 501, NULL,
714 + US"ENVID can be specified once only");
715 + goto COMMAND_LOOP;
716 + }
717 + dsn_envid = string_copy(value);
718 + DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid);
719 + break;
720 +#endif
721 +
722 /* Handle the AUTH extension. If the value given is not "<>" and either
723 the ACL says "yes" or there is no ACL but the sending host is
724 authenticated, we set it up as the authenticated sender. However, if the
725 @@ -3633,6 +3693,89 @@
726 rcpt_fail_count++;
727 break;
728 }
729 +
730 + #ifdef SUPPORT_DSN
731 + /* Set the DSN flags orcpt and dsn_flags from the session*/
732 + orcpt = NULL;
733 + flags = 0;
734 +
735 + if (esmtp) for(;;)
736 + {
737 + uschar *name, *value, *end;
738 + int size;
739 +
740 + if (!extract_option(&name, &value))
741 + {
742 + break;
743 + }
744 +
745 + if (strcmpic(name, US"ORCPT") == 0)
746 + {
747 + /* Check whether orcpt has been already set */
748 + if (orcpt != NULL) {
749 + synprot_error(L_smtp_syntax_error, 501, NULL,
750 + US"ORCPT can be specified once only");
751 + goto COMMAND_LOOP;
752 + }
753 + orcpt = string_copy(value);
754 + DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", orcpt);
755 + }
756 +
757 + else if (strcmpic(name, US"NOTIFY") == 0)
758 + {
759 + /* Check if the notify flags have been already set */
760 + if (flags > 0)
761 + {
762 + synprot_error(L_smtp_syntax_error, 501, NULL,
763 + US"NOTIFY can be specified once only");
764 + goto COMMAND_LOOP;
765 + }
766 + if (strcmpic(value, US"NEVER") == 0) flags |= rf_notify_never; else
767 + {
768 + uschar *p = value;
769 + while (*p != 0)
770 + {
771 + uschar *pp = p;
772 + while (*pp != 0 && *pp != ',') pp++;
773 + if (*pp == ',') *pp++ = 0;
774 + if (strcmpic(p, US"SUCCESS") == 0) {
775 + DEBUG(D_receive) debug_printf("GC: Setting notify success\n");
776 + flags |= rf_notify_success;
777 + }
778 + else if (strcmpic(p, US"FAILURE") == 0) {
779 + DEBUG(D_receive) debug_printf("GC: Setting notify failure\n");
780 + flags |= rf_notify_failure;
781 + }
782 + else if (strcmpic(p, US"DELAY") == 0) {
783 + DEBUG(D_receive) debug_printf("GC: Setting notify delay\n");
784 + flags |= rf_notify_delay;
785 + }
786 + else
787 + {
788 + /* Catch any strange values */
789 + synprot_error(L_smtp_syntax_error, 501, NULL,
790 + US"Invalid value for NOTIFY parameter");
791 + goto COMMAND_LOOP;
792 + }
793 + p = pp;
794 + }
795 + DEBUG(D_receive) debug_printf("DSN Flags: %x\n", flags);
796 + }
797 + }
798 +
799 + /* Unknown option. Stick back the terminator characters and break
800 + the loop. An error for a malformed address will occur. */
801 +
802 + else
803 + {
804 + DEBUG(D_receive) debug_printf("Invalid dsn command: %s : %s\n", name, value);
805 + name[-1] = ' ';
806 + value[-1] = '=';
807 + break;
808 + }
809 + }
810 + #endif
811 +
812
813 /* Apply SMTP rewriting then extract the working address. Don't allow "<>"
814 as a recipient address */
815 @@ -3747,6 +3890,24 @@
816 if (user_msg == NULL) smtp_printf("250 Accepted\r\n");
817 else smtp_user_msg(US"250", user_msg);
818 receive_add_recipient(recipient, -1);
819 +
820 + #ifdef SUPPORT_DSN
821 +
822 + /* Set the dsn flags in the recipients_list */
823 + if (orcpt != NULL)
824 + recipients_list[recipients_count-1].orcpt = orcpt;
825 + else
826 + recipients_list[recipients_count-1].orcpt = NULL;
827 +
828 + if (flags != 0)
829 + recipients_list[recipients_count-1].dsn_flags = flags;
830 + else
831 + recipients_list[recipients_count-1].dsn_flags = 0;
832 + debug_printf("DSN-AJ(smtp-in): orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags);
833 +
834 +
835 + #endif
836 +
837 }
838
839 /* The recipient was discarded */
840 diff -Naur exim-4.82_RC5.orig/src/spool_in.c exim-4.82_RC5/src/spool_in.c
841 --- exim-4.82_RC5.orig/src/spool_in.c 2013-10-27 21:46:25.000000000 +0100
842 +++ exim-4.82_RC5/src/spool_in.c 2013-10-27 21:47:32.000000000 +0100
843 @@ -293,6 +293,13 @@
844 spam_score_int = NULL;
845 #endif
846
847 +#ifdef SUPPORT_DSN
848 +#ifndef COMPILE_UTILITY
849 +dsn_ret = 0;
850 +dsn_envid = NULL;
851 +#endif /* COMPILE_UTILITY */
852 +#endif
853 +
854 /* Generate the full name and open the file. If message_subdir is already
855 set, just look in the given directory. Otherwise, look in both the split
856 and unsplit directories, as for the data file above. */
857 @@ -467,6 +474,19 @@
858 case 'd':
859 if (Ustrcmp(p, "eliver_firsttime") == 0)
860 deliver_firsttime = TRUE;
861 + #ifdef SUPPORT_DSN
862 + #ifndef COMPILE_UTILITY
863 + /* Check if the dsn flags have been set in the header file */
864 + else if (Ustrncmp(p, "sn_ret", 6) == 0)
865 + {
866 + dsn_ret= atoi(big_buffer + 8);
867 + }
868 + else if (Ustrncmp(p, "sn_envid", 8) == 0)
869 + {
870 + dsn_envid = string_copy(big_buffer + 11);
871 + }
872 + #endif /* COMPILE_UTILITY */
873 + #endif
874 break;
875
876 case 'f':
877 @@ -554,7 +574,7 @@
878 tls_in.sni = string_unprinting(string_copy(big_buffer + 9));
879 break;
880 #endif
881 -
882 +
883 default: /* Present because some compilers complain if all */
884 break; /* possibilities are not covered. */
885 }
886 @@ -604,6 +624,10 @@
887 {
888 int nn;
889 int pno = -1;
890 + #ifdef SUPPORT_DSN
891 + int dsn_flags = 0;
892 + uschar *orcpt = NULL;
893 + #endif
894 uschar *errors_to = NULL;
895 uschar *p;
896
897 @@ -672,10 +696,19 @@
898 }
899
900 /* Handle current format Exim 4 spool files */
901 + /* Spool file is modified if DSN is supported
902 + Original was "address errors_to len(errors_to),pno
903 + New for DSN support is now:
904 + "address errors_to orcpt len(errors_to),len(orcpt),pno,dsn_flags */
905
906 else if (*p == '#')
907 {
908 int flags;
909 +
910 + #ifndef COMPILE_UTILITY
911 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - Exim 4 standard format spoolfile\n");
912 + #endif /* COMPILE_UTILITY */
913 +
914 (void)sscanf(CS p+1, "%d", &flags);
915
916 if ((flags & 0x01) != 0) /* one_time data exists */
917 @@ -688,15 +721,82 @@
918 {
919 p -= len;
920 errors_to = string_copy(p);
921 + }
922 + }
923 +
924 + *(--p) = 0; /* Terminate address */
925 + }
926 + #ifdef SUPPORT_DSN
927 + else if (*p == '!') /* Handle Exim4 + DSN spool files */
928 + {
929 + int flags;
930 + int temp_dsn_flags;
931 +
932 + #ifndef COMPILE_UTILITY
933 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - C&W DSN format spoolfile\n");
934 + #endif /* COMPILE_UTILITY */
935 +
936 + sscanf(CS p+1, "%d,%d", &flags, &temp_dsn_flags);
937 +
938 + if (((flags & 0x01) != 0) || (temp_dsn_flags > 0)) /* one_time data or dsn_flags exist */
939 + {
940 + int len;
941 + int len_orcpt;
942 +
943 + #ifndef COMPILE_UTILITY
944 + DEBUG(D_deliver) debug_printf("**** spool_in dsn_flags = 0\n");
945 + #endif /* COMPILE_UTILITY */
946 +
947 + dsn_flags = 0;
948 +
949 + while (isdigit(*(--p)) || *p == ',' || *p == '-');
950 + sscanf(CS p+1, "%d,%d,%d,%d", &len, &len_orcpt, &pno, &dsn_flags);
951 +
952 + *p = 0;
953 + if (len_orcpt > 0)
954 + {
955 + p -= len_orcpt;
956 + orcpt = string_copy(p);
957 }
958 + *(--p) = 0; /* change the space to a NULL */
959 +
960 + if (len > 0)
961 + {
962 + p -= len;
963 + errors_to = string_copy(p);
964 + }
965 }
966
967 *(--p) = 0; /* Terminate address */
968 }
969 + #endif
970 + #ifndef COMPILE_UTILITY
971 + else
972 + {
973 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - No additional fields\n");
974 + }
975 + #endif /* COMPILE_UTILITY */
976 +
977 + #ifdef SUPPORT_DSN
978 + #ifndef COMPILE_UTILITY
979 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
980 + big_buffer, errors_to, orcpt, dsn_flags);
981 + #endif /* COMPILE_UTILITY */
982 + #endif
983 + #ifndef SUPPORT_DSN
984 + #ifndef COMPILE_UTILITY
985 + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s|\n",
986 + big_buffer, errors_to);
987 + #endif /* COMPILE_UTILITY */
988 + #endif
989
990 recipients_list[recipients_count].address = string_copy(big_buffer);
991 recipients_list[recipients_count].pno = pno;
992 recipients_list[recipients_count].errors_to = errors_to;
993 + #ifdef SUPPORT_DSN
994 + recipients_list[recipients_count].orcpt = orcpt;
995 + recipients_list[recipients_count].dsn_flags = dsn_flags;
996 + #endif
997 }
998
999 /* The remainder of the spool header file contains the headers for the message,
1000 diff -Naur exim-4.82_RC5.orig/src/spool_out.c exim-4.82_RC5/src/spool_out.c
1001 --- exim-4.82_RC5.orig/src/spool_out.c 2013-10-27 21:46:25.000000000 +0100
1002 +++ exim-4.82_RC5/src/spool_out.c 2013-10-27 21:47:32.000000000 +0100
1003 @@ -234,6 +234,15 @@
1004 if (tls_in.sni != NULL) fprintf(f, "-tls_sni %s\n", string_printing(tls_in.sni));
1005 #endif
1006
1007 +#ifdef SUPPORT_DSN
1008 +/* Write the dsn flags to the spool header file */
1009 +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid);
1010 +if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid);
1011 +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret);
1012 +if (dsn_ret != 0) fprintf(f, "-dsn_ret %d\n", dsn_ret);
1013 +#endif
1014 +
1015 +
1016 /* To complete the envelope, write out the tree of non-recipients, followed by
1017 the list of recipients. These won't be disjoint the first time, when no
1018 checking has been done. If a recipient is a "one-time" alias, it is followed by
1019 @@ -244,14 +253,36 @@
1020 for (i = 0; i < recipients_count; i++)
1021 {
1022 recipient_item *r = recipients_list + i;
1023 - if (r->pno < 0 && r->errors_to == NULL)
1024 +#ifdef SUPPORT_DSN
1025 +DEBUG(D_deliver) debug_printf("DSN: Flags :%d\n", r->dsn_flags);
1026 +#endif
1027 + if (r->pno < 0 && r->errors_to == NULL
1028 + #ifdef SUPPORT_DSN
1029 + && r->dsn_flags == 0
1030 + #endif
1031 + )
1032 fprintf(f, "%s\n", r->address);
1033 else
1034 {
1035 uschar *errors_to = (r->errors_to == NULL)? US"" : r->errors_to;
1036 + #ifdef SUPPORT_DSN
1037 + uschar *orcpt = (r->orcpt == NULL)? US"" : r->orcpt;
1038 + fprintf(f, "%s %s %s %d,%d,%d,%d!1\n", r->address, errors_to, orcpt,
1039 + Ustrlen(errors_to), Ustrlen(orcpt), r->pno, r->dsn_flags);
1040 + #else
1041 fprintf(f, "%s %s %d,%d#1\n", r->address, errors_to,
1042 Ustrlen(errors_to), r->pno);
1043 + #endif
1044 }
1045 +
1046 + #ifdef SUPPORT_DSN
1047 + DEBUG(D_deliver) debug_printf("DSN :**** SPOOL_OUT - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n",
1048 + r->address, r->errors_to, r->orcpt, r->dsn_flags);
1049 + #endif
1050 + #ifndef SUPPORT_DSN
1051 + DEBUG(D_deliver) debug_printf("**** SPOOL_OUT - address: |%s| errorsto: |%s|\n",
1052 + r->address, r->errors_to);
1053 + #endif
1054 }
1055
1056 /* Put a blank line before the headers */
1057 diff -Naur exim-4.82_RC5.orig/src/structs.h exim-4.82_RC5/src/structs.h
1058 --- exim-4.82_RC5.orig/src/structs.h 2013-10-27 21:46:25.000000000 +0100
1059 +++ exim-4.82_RC5/src/structs.h 2013-10-27 21:47:32.000000000 +0100
1060 @@ -282,7 +282,9 @@
1061 BOOL verify_sender; /* Use this router when verifying a sender */
1062 BOOL uid_set; /* Flag to indicate uid is set */
1063 BOOL unseen; /* If TRUE carry on, even after success */
1064 -
1065 +#ifdef SUPPORT_DSN
1066 + BOOL dsn_process; /* If TRUE, activate DSN for this router */
1067 +#endif
1068 int self_code; /* Encoded version of "self" */
1069 uid_t uid; /* Fixed uid value */
1070 gid_t gid; /* Fixed gid value */
1071 @@ -547,6 +549,12 @@
1072 uschar *auth_id; /* auth "login" name used by transport */
1073 uschar *auth_sndr; /* AUTH arg to SMTP MAIL, used by transport */
1074
1075 + #ifdef SUPPORT_DSN
1076 + uschar *dsn_orcpt; /* DSN orcpt value */
1077 + int dsn_flags; /* DSN flags */
1078 + uschar *dsn_aware; /* DSN aware flag */
1079 + #endif
1080 +
1081 uid_t uid; /* uid for transporting */
1082 gid_t gid; /* gid for transporting */
1083
1084 diff -Naur exim-4.82_RC5.orig/src/transport.c exim-4.82_RC5/src/transport.c
1085 --- exim-4.82_RC5.orig/src/transport.c 2013-10-27 21:46:25.000000000 +0100
1086 +++ exim-4.82_RC5/src/transport.c 2013-10-27 21:47:32.000000000 +0100
1087 @@ -1802,6 +1802,11 @@
1088
1089 argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
1090
1091 + #ifdef SUPPORT_DSN
1092 + /* Call with the dsn flag */
1093 + if (smtp_use_dsn) argv[i++] = US"-MCD";
1094 + #endif
1095 +
1096 if (smtp_authenticated) argv[i++] = US"-MCA";
1097
1098 #ifdef SUPPORT_TLS
1099 diff -Naur exim-4.82_RC5.orig/src/transports/smtp.c exim-4.82_RC5/src/transports/smtp.c
1100 --- exim-4.82_RC5.orig/src/transports/smtp.c 2013-10-27 21:46:25.000000000 +0100
1101 +++ exim-4.82_RC5/src/transports/smtp.c 2013-10-27 21:47:32.000000000 +0100
1102 @@ -242,6 +242,16 @@
1103 #endif
1104 };
1105
1106 +#ifdef SUPPORT_DSN
1107 +/* some DSN flags for use later */
1108 +
1109 +static int rf_list[] = {rf_notify_never, rf_notify_success,
1110 + rf_notify_failure, rf_notify_delay };
1111 +
1112 +static uschar *rf_names[] = { "NEVER", "SUCCESS", "FAILURE", "DELAY" };
1113 +#endif
1114 +
1115 +
1116
1117 /* Local statics */
1118
1119 @@ -1079,6 +1089,27 @@
1120 else if (new[0] != 0) local_authenticated_sender = new;
1121 }
1122
1123 +#ifdef SUPPORT_DSN
1124 +/* Add any DSN flags to the mail command */
1125 +
1126 +if (smtp_use_dsn)
1127 + {
1128 + uschar *p = buffer;
1129 + if (dsn_ret == dsn_ret_hdrs)
1130 + {
1131 + strcpy(p, " RET=HDRS");
1132 + while (*p) p++;
1133 + }
1134 + else if (dsn_ret == dsn_ret_full)
1135 + {
1136 + strcpy(p, " RET=FULL");
1137 + while (*p) p++;
1138 + }
1139 + if (dsn_envid != NULL)
1140 + string_format(p, sizeof(buffer) - (p-buffer), " ENVID=%s", dsn_envid);
1141 + }
1142 +#endif
1143 +
1144 /* Add the authenticated sender address if present */
1145
1146 if ((smtp_authenticated || ob->authenticated_sender_force) &&
1147 @@ -1587,6 +1618,14 @@
1148 {DEBUG(D_transport) debug_printf("PRDR usable\n");}
1149 #endif
1150
1151 + #ifdef SUPPORT_DSN
1152 + /* Note if the server supports DSN */
1153 + smtp_use_dsn = dsn &&
1154 + esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0,
1155 + PCRE_EOPT, NULL, 0) >= 0;
1156 + DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn);
1157 + #endif
1158 +
1159 /* Note if the response to EHLO specifies support for the AUTH extension.
1160 If it has, check that this host is one we want to authenticate to, and do
1161 the business. The host name and address must be available when the
1162 @@ -1746,18 +1785,66 @@
1163 int count;
1164 BOOL no_flush;
1165
1166 + #ifdef SUPPORT_DSN
1167 + /* philb - set dsn_aware flag for this recipient */
1168 + if(smtp_use_dsn)
1169 + addr->dsn_aware = string_copy("Y");
1170 + else
1171 + addr->dsn_aware = string_copy("N");
1172 + #endif
1173 +
1174 if (addr->transport_return != PENDING_DEFER) continue;
1175
1176 address_count++;
1177 no_flush = smtp_use_pipelining && (!mua_wrapper || addr->next != NULL);
1178
1179 + #ifdef SUPPORT_DSN
1180 + /* Add any DSN flags to the rcpt command and add to the sent string */
1181 +
1182 + p = buffer;
1183 + *p = 0;
1184 +
1185 + if (smtp_use_dsn)
1186 + {
1187 + if ((addr->dsn_flags & rf_dsnflags) != 0)
1188 + {
1189 + int i;
1190 + BOOL first = TRUE;
1191 + strcpy(p, " NOTIFY=");
1192 + while (*p) p++;
1193 + for (i = 0; i < 4; i++)
1194 + {
1195 + if ((addr->dsn_flags & rf_list[i]) != 0)
1196 + {
1197 + if (!first) *p++ = ',';
1198 + first = FALSE;
1199 + strcpy(p, rf_names[i]);
1200 + while (*p) p++;
1201 + }
1202 + }
1203 + }
1204 +
1205 + if (addr->dsn_orcpt != NULL)
1206 + string_format(p, sizeof(buffer) - (p-buffer), " ORCPT=%s",
1207 + addr->dsn_orcpt);
1208 + }
1209 +
1210 + #endif
1211 +
1212 +
1213 /* Now send the RCPT command, and process outstanding responses when
1214 necessary. After a timeout on RCPT, we just end the function, leaving the
1215 yield as OK, because this error can often mean that there is a problem with
1216 just one address, so we don't want to delay the host. */
1217
1218 + #ifdef SUPPORT_DSN
1219 + count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s%s\r\n",
1220 + transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr, buffer);
1221 + #else
1222 count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n",
1223 transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr);
1224 + #endif
1225 +
1226 if (count < 0) goto SEND_FAILED;
1227 if (count > 0)
1228 {