]>
Commit | Line | Data |
---|---|---|
e859f219 AM |
1 | diff -urN exim-4.62-orig/README.DSN exim-4.62-dsn/README.DSN |
2 | --- exim-4.62-orig/README.DSN 1970-01-01 01:00:00.000000000 +0100 | |
3 | +++ exim-4.62-dsn/README.DSN 2006-05-17 12:59:03.000000000 +0100 | |
4 | @@ -0,0 +1,104 @@ | |
5 | +Exim DSN Patch (4.60) | |
6 | +--------------------- | |
7 | + | |
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. | |
12 | + | |
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. | |
17 | + | |
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. | |
21 | + | |
22 | +Install | |
23 | +------- | |
24 | +cd into the source tree for a vanilla exim | |
25 | + | |
26 | +patch -p1 </path/to/patch/file.patch | |
27 | + | |
28 | +Example :- | |
29 | +[root@linuxbuild exim-4.60-test]# patch -p1 <../exim.dsn.patch.460 | |
30 | + | |
31 | +Expected Output :- | |
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 | |
49 | + | |
50 | + | |
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. | |
53 | + | |
54 | +Use | |
55 | +--- | |
56 | + | |
57 | +The facility (once compiled in) can be turned on for a particular router via the | |
58 | +dsn_process directive Eg :- | |
59 | + | |
60 | +dest_delivery_int: | |
61 | + driver = manualroute | |
62 | + domains = +relay_to_domains | |
63 | + condition = ${if eq {${lc:$sender_address_domain}}\ | |
64 | + {domain.com}\ | |
65 | + {yes}{no}\ | |
66 | + } | |
67 | + dsn_process | |
68 | + hide route_data = ${lc:${extract{mailHost}{$address_data}{$value}{}}} | |
69 | + transport = remote_smtp | |
70 | + | |
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 | |
74 | +transport or not. | |
75 | + | |
76 | + | |
77 | +Credits | |
78 | +------- | |
79 | + | |
80 | +The original work for the patch was done by Philip Hazel in Exim 3 | |
81 | + | |
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) | |
88 | + | |
89 | +Contributions | |
90 | +------------- | |
91 | +Andrey J. Melnikoff (TEMHOTA) (temnota@kmv.ru) | |
92 | + | |
93 | + | |
94 | +ChangeLog | |
95 | +--------- | |
96 | + | |
97 | +14-Apr-2006 : Changed subject to "Delivery Status Notification" | |
98 | + | |
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 | |
101 | + | |
102 | + | |
103 | + | |
104 | +Support for this patch (limited though it is) will only be provided through the SourceForge | |
105 | +project page (http://sourceforge.net/projects/eximdsn/) | |
106 | + | |
107 | +-- | |
108 | +Andrew Johnson Cable & Wireless | |
109 | diff -urN exim-4.62-orig/src/config.h.defaults exim-4.62-dsn/src/config.h.defaults | |
110 | --- exim-4.62-orig/src/config.h.defaults 2006-04-28 11:32:22.000000000 +0100 | |
111 | +++ exim-4.62-dsn/src/config.h.defaults 2006-05-17 12:59:03.000000000 +0100 | |
112 | @@ -123,6 +123,7 @@ | |
113 | #define SUPPORT_MOVE_FROZEN_MESSAGES | |
114 | #define SUPPORT_PAM | |
115 | #define SUPPORT_TLS | |
116 | +#define SUPPORT_DSN | |
117 | #define SUPPORT_TRANSLATE_IP_ADDRESS | |
118 | ||
119 | #define SYSLOG_LOG_PID | |
120 | diff -urN exim-4.62-orig/src/deliver.c exim-4.62-dsn/src/deliver.c | |
121 | --- exim-4.62-orig/src/deliver.c 2006-04-28 11:32:22.000000000 +0100 | |
122 | +++ exim-4.62-dsn/src/deliver.c 2006-05-17 12:59:03.000000000 +0100 | |
123 | @@ -65,6 +65,9 @@ | |
124 | static address_item *addr_remote = NULL; | |
125 | static address_item *addr_route = NULL; | |
126 | static address_item *addr_succeed = NULL; | |
127 | +#ifdef SUPPORT_DSN | |
128 | +static address_item *addr_dsntmp = NULL; | |
129 | +#endif | |
130 | ||
131 | static FILE *message_log = NULL; | |
132 | static BOOL update_spool; | |
133 | @@ -2859,6 +2862,15 @@ | |
134 | break; | |
135 | #endif | |
136 | ||
137 | + #ifdef SUPPORT_DSN | |
138 | + case 'D': | |
139 | + if (addr == NULL) break; | |
140 | + addr->dsn_aware = (*ptr)? string_copy(ptr) : string_copy(" "); | |
141 | + while (*ptr++); | |
142 | + DEBUG(D_deliver) debug_printf("DSN read: addr->dsn_aware = %s\n", addr->dsn_aware); | |
143 | + break; | |
144 | + #endif | |
145 | + | |
146 | case 'A': | |
147 | if (addr == NULL) | |
148 | { | |
149 | @@ -3928,6 +3940,15 @@ | |
150 | } | |
151 | #endif | |
152 | ||
153 | + #ifdef SUPPORT_DSN | |
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); | |
160 | + #endif | |
161 | + | |
162 | /* Retry information: for most success cases this will be null. */ | |
163 | ||
164 | for (r = addr->retries; r != NULL; r = r->next) | |
165 | @@ -5068,6 +5089,14 @@ | |
166 | if (r->pno >= 0) | |
167 | new->onetime_parent = recipients_list[r->pno].address; | |
168 | ||
169 | + #ifdef SUPPORT_DSN | |
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); | |
175 | + #endif | |
176 | + | |
177 | switch (process_recipients) | |
178 | { | |
179 | /* RECIP_DEFER is set when a system filter freezes a message. */ | |
180 | @@ -5992,6 +6021,12 @@ | |
181 | regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE); | |
182 | #endif | |
183 | ||
184 | + #ifdef SUPPORT_DSN | |
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); | |
188 | + #endif | |
189 | + | |
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 | @@ -6096,6 +6131,179 @@ | |
194 | ||
195 | else if (!dont_deliver) retry_update(&addr_defer, &addr_failed, &addr_succeed); | |
196 | ||
197 | +#ifdef SUPPORT_DSN | |
198 | +/* ********** philb - Send DSN for successful messages */ | |
199 | + | |
200 | +addr_dsntmp = addr_succeed; | |
201 | + | |
202 | +while(addr_dsntmp != NULL) | |
203 | +{ | |
204 | + BOOL dsn_sendmessage = FALSE; | |
205 | + uschar dsnmsgbuf[4096]; | |
206 | + | |
207 | + DEBUG(D_deliver) | |
208 | + debug_printf("DSN: processing router : %s\n", addr_dsntmp->router->name); | |
209 | + | |
210 | + DEBUG(D_deliver) | |
211 | + debug_printf("DSN: processing successful delivery address: %s\n", addr_dsntmp->address); | |
212 | + | |
213 | + if (testflag(addr_dsntmp, af_ignore_error)) | |
214 | + { | |
215 | + DEBUG(D_deliver) | |
216 | + debug_printf("DSN: Ignore error for: %s\n", addr_dsntmp->address); | |
217 | + } | |
218 | + else | |
219 | + { | |
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(" "); | |
224 | + } | |
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); | |
229 | + | |
230 | + /* Process the flags */ | |
231 | + if((addr_dsntmp->dsn_flags & rf_dsnflags) != 0) | |
232 | + { | |
233 | + /* We've got at least one flag set */ | |
234 | + | |
235 | + /* set flag so we don't send bounces */ | |
236 | + setflag(addr_dsntmp, af_ignore_error); | |
237 | + | |
238 | + if((addr_dsntmp->dsn_flags & rf_notify_never) != 0) | |
239 | + { | |
240 | + DEBUG(D_deliver) debug_printf("DSN: NEVER FLAG\n"); | |
241 | + | |
242 | + /* nothing to do here */ | |
243 | + } | |
244 | + | |
245 | + if((addr_dsntmp->dsn_flags & rf_notify_success) != 0) | |
246 | + { | |
247 | + DEBUG(D_deliver) debug_printf("DSN: SUCCESS FLAG\n"); | |
248 | + | |
249 | + dsn_sendmessage = TRUE; | |
250 | + } | |
251 | + | |
252 | + if((addr_dsntmp->dsn_flags & rf_notify_failure) != 0) | |
253 | + { | |
254 | + DEBUG(D_deliver) debug_printf("DSN: FAILURE FLAG\n"); | |
255 | + | |
256 | + /* allow bounce messages */ | |
257 | + clearflag(addr_dsntmp, af_ignore_error); | |
258 | + } | |
259 | + | |
260 | + if((addr_dsntmp->dsn_flags & rf_notify_delay) != 0) | |
261 | + { | |
262 | + DEBUG(D_deliver) debug_printf("DSN: DELAY FLAG\n"); | |
263 | + | |
264 | + /* hmm, what to do here? */ | |
265 | + } | |
266 | + } | |
267 | + | |
268 | + if ((addr_dsntmp->dsn_aware != 0) && (addr_dsntmp->dsn_aware[0] != 'Y') && (dsn_sendmessage == TRUE) && (addr_dsntmp->router->dsn_process == TRUE)) | |
269 | + { | |
270 | + pid_t pid; | |
271 | + int fd; | |
272 | + | |
273 | + /* remote MTA does not support DSN, so we need to send message */ | |
274 | + | |
275 | + /* create exim process to send message */ | |
276 | + pid = child_open_exim(&fd); | |
277 | + | |
278 | + DEBUG(D_deliver) debug_printf("DSN: child_open_exim returns: %d\n", pid); | |
279 | + | |
280 | + if (pid < 0) /* Creation of child failed */ | |
281 | + { | |
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)); | |
285 | + | |
286 | + DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n"); | |
287 | + | |
288 | + } | |
289 | + else /* Creation of child succeeded */ | |
290 | + { | |
291 | + FILE *f = fdopen(fd, "wb"); | |
292 | + int topt = topt_add_return_path; | |
293 | + uschar boundaryStr[64]; | |
294 | + | |
295 | + DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address); | |
296 | + | |
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); | |
300 | + | |
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; | |
303 | + | |
304 | + if (errors_reply_to != NULL) fprintf(f,"Reply-To: %s\n", errors_reply_to); | |
305 | + | |
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"); | |
312 | + | |
313 | + fprintf(f,"--%s\n", boundaryStr); | |
314 | + fprintf(f,"Content-type: text/plain; charset=us-ascii\n\n"); | |
315 | + | |
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); | |
321 | + } else { | |
322 | + fprintf(f,"<%s> (relayed via non \"Remote SMTP\" router)\n\n", addr_dsntmp->address); | |
323 | + } | |
324 | + | |
325 | + fprintf(f,"--%s\n", boundaryStr); | |
326 | + fprintf(f,"Content-type: message/delivery-status\n\n"); | |
327 | + | |
328 | + if (dsn_envid) { /* Test for NULL added by GC */ | |
329 | + fprintf(f,"Original-Envelope-Id: %s\n", dsn_envid); | |
330 | + } | |
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); | |
334 | + } | |
335 | + fprintf(f,"Action: delivered\n\n"); | |
336 | + | |
337 | + fprintf(f,"--%s\n", boundaryStr); | |
338 | + fprintf(f,"Content-type: message/rfc822\n\n"); | |
339 | + | |
340 | + fflush(f); | |
341 | + transport_filter_argv = NULL; /* Just in case */ | |
342 | + return_path = sender_address; /* In case not previously set */ | |
343 | + | |
344 | + /* Write the original email out */ | |
345 | + transport_write_message(NULL, fileno(f), topt, 2048, NULL, NULL, NULL, NULL, NULL, 0); | |
346 | + fflush(f); | |
347 | + | |
348 | + fprintf(f,"\n"); | |
349 | + fprintf(f,"--%s--\n", boundaryStr); | |
350 | + | |
351 | + fflush(f); | |
352 | + fclose(f); | |
353 | + rc = child_close(pid, 0); /* Waits for child to close, no timeout */ | |
354 | + } | |
355 | + } | |
356 | + else | |
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"); | |
361 | + } | |
362 | + } | |
363 | + | |
364 | + addr_dsntmp = addr_dsntmp->next; | |
365 | +} | |
366 | + | |
367 | +/* ********** philb - end of mod */ | |
368 | +#endif | |
369 | + | |
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.62-orig/src/exim.c exim-4.62-dsn/src/exim.c | |
374 | --- exim-4.62-orig/src/exim.c 2006-04-28 11:32:22.000000000 +0100 | |
375 | +++ exim-4.62-dsn/src/exim.c 2006-05-17 13:12:24.000000000 +0100 | |
376 | @@ -920,6 +920,9 @@ | |
377 | #ifdef EXPERIMENTAL_DOMAINKEYS | |
378 | fprintf(f, " Experimental_DomainKeys"); | |
379 | #endif | |
380 | +#ifdef SUPPORT_DSN | |
381 | + fprintf(f, " C&W_DSN_1.2"); | |
382 | +#endif | |
383 | fprintf(f, "\n"); | |
384 | ||
385 | fprintf(f, "Lookups:"); | |
386 | @@ -2184,6 +2187,16 @@ | |
387 | break; | |
388 | } | |
389 | ||
390 | + #ifdef SUPPORT_DSN | |
391 | + /* -MCD: set the smtp_use_dsn flag; this indicates that the host | |
392 | + that exim is connected to supports the esmtp extension DSN */ | |
393 | + else if (strcmp(argrest, "CD") == 0) | |
394 | + { | |
395 | + smtp_use_dsn = TRUE; | |
396 | + break; | |
397 | + } | |
398 | + #endif | |
399 | + | |
400 | /* -MCP: set the smtp_use_pipelining flag; this is useful only when | |
401 | it preceded -MC (see above) */ | |
402 | ||
403 | diff -urN exim-4.62-orig/src/globals.c exim-4.62-dsn/src/globals.c | |
404 | --- exim-4.62-orig/src/globals.c 2006-04-28 11:32:22.000000000 +0100 | |
405 | +++ exim-4.62-dsn/src/globals.c 2006-05-17 12:59:03.000000000 +0100 | |
406 | @@ -121,6 +121,13 @@ | |
407 | uschar *tls_verify_hosts = NULL; | |
408 | #endif | |
409 | ||
410 | +#ifdef SUPPORT_DSN | |
411 | +BOOL dsn = TRUE; | |
412 | +uschar *dsn_envid = NULL; | |
413 | +int dsn_ret = 0; | |
414 | +const pcre *regex_DSN = NULL; | |
415 | +BOOL smtp_use_dsn = FALSE; | |
416 | +#endif | |
417 | ||
418 | /* Input-reading functions for messages, so we can use special ones for | |
419 | incoming TCP/IP. The defaults use stdin. We never need these for any | |
420 | @@ -267,6 +274,11 @@ | |
421 | NULL, /* cipher */ | |
422 | NULL, /* peerdn */ | |
423 | #endif | |
424 | + #ifdef SUPPORT_DSN | |
425 | + NULL, /* dsn_orcpt */ | |
426 | + 0, /* dsn_flags */ | |
427 | + NULL, /* dsn_aware */ | |
428 | + #endif | |
429 | (uid_t)(-1), /* uid */ | |
430 | (gid_t)(-1), /* gid */ | |
431 | 0, /* flags */ | |
432 | @@ -949,6 +961,9 @@ | |
433 | TRUE, /* verify_sender */ | |
434 | FALSE, /* uid_set */ | |
435 | FALSE, /* unseen */ | |
436 | +#ifdef SUPPORT_DSN | |
437 | + FALSE, /* dsn_process */ | |
438 | +#endif | |
439 | ||
440 | self_freeze, /* self_code */ | |
441 | (uid_t)(-1), /* uid */ | |
442 | @@ -958,6 +973,7 @@ | |
443 | NULL, /* transport instance */ | |
444 | NULL, /* pass_router */ | |
445 | NULL /* redirect_router */ | |
446 | + | |
447 | }; | |
448 | ||
449 | ip_address_item *running_interfaces = NULL; | |
450 | diff -urN exim-4.62-orig/src/globals.h exim-4.62-dsn/src/globals.h | |
451 | --- exim-4.62-orig/src/globals.h 2006-04-28 11:32:22.000000000 +0100 | |
452 | +++ exim-4.62-dsn/src/globals.h 2006-05-17 12:59:03.000000000 +0100 | |
453 | @@ -85,6 +85,13 @@ | |
454 | extern uschar *tls_verify_hosts; /* Mandatory client verification */ | |
455 | #endif | |
456 | ||
457 | +#ifdef SUPPORT_DSN | |
458 | +extern BOOL dsn; /* FALSE if DSN not to be used */ | |
459 | +extern uschar *dsn_envid; /* DSN envid string */ | |
460 | +extern int dsn_ret; /* DSN ret type*/ | |
461 | +extern const pcre *regex_DSN; /* For recognizing DSN settings */ | |
462 | +extern BOOL smtp_use_dsn; /* Global for passed connections */ | |
463 | +#endif | |
464 | ||
465 | /* Input-reading functions for messages, so we can use special ones for | |
466 | incoming TCP/IP. */ | |
467 | diff -urN exim-4.62-orig/src/local_scan.h exim-4.62-dsn/src/local_scan.h | |
468 | --- exim-4.62-orig/src/local_scan.h 2006-04-28 11:32:22.000000000 +0100 | |
469 | +++ exim-4.62-dsn/src/local_scan.h 2006-05-17 12:59:03.000000000 +0100 | |
470 | @@ -123,9 +123,13 @@ | |
471 | field is always NULL except for one_time aliases that had errors_to on the | |
472 | routers that generated them. */ | |
473 | ||
474 | +/* Added the dsn attributes orcpt and dsn_flags for DSN support*/ | |
475 | + | |
476 | typedef struct recipient_item { | |
477 | uschar *address; /* the recipient address */ | |
478 | int pno; /* parent number for "one_time" alias, or -1 */ | |
479 | + uschar *orcpt; /* DSN orcpt */ | |
480 | + int dsn_flags; /* DSN flags */ | |
481 | uschar *errors_to; /* the errors_to address or NULL */ | |
482 | #ifdef EXPERIMENTAL_BRIGHTMAIL | |
483 | uschar *bmi_optin; | |
484 | diff -urN exim-4.62-orig/src/macros.h exim-4.62-dsn/src/macros.h | |
485 | --- exim-4.62-orig/src/macros.h 2006-04-28 11:32:22.000000000 +0100 | |
486 | +++ exim-4.62-dsn/src/macros.h 2006-05-17 12:59:03.000000000 +0100 | |
487 | @@ -733,6 +733,22 @@ | |
488 | #define topt_no_body 0x040 /* Omit body */ | |
489 | #define topt_escape_headers 0x080 /* Apply escape check to headers */ | |
490 | ||
491 | +/* Flags for recipient_block, used in DSN support */ | |
492 | + | |
493 | +#define rf_onetime 0x01 /* A one-time alias */ | |
494 | +#define rf_notify_never 0x02 /* NOTIFY= settings */ | |
495 | +#define rf_notify_success 0x04 | |
496 | +#define rf_notify_failure 0x08 | |
497 | +#define rf_notify_delay 0x10 | |
498 | + | |
499 | +#define rf_dsnflags (rf_notify_never | rf_notify_success | \ | |
500 | + rf_notify_failure | rf_notify_delay) | |
501 | + | |
502 | +/* DSN RET types */ | |
503 | + | |
504 | +#define dsn_ret_full 1 | |
505 | +#define dsn_ret_hdrs 2 | |
506 | + | |
507 | /* Codes for the host_find_failed option. */ | |
508 | ||
509 | #define hff_freeze 0 | |
510 | diff -urN exim-4.62-orig/src/readconf.c exim-4.62-dsn/src/readconf.c | |
511 | --- exim-4.62-orig/src/readconf.c 2006-04-28 11:32:22.000000000 +0100 | |
512 | +++ exim-4.62-dsn/src/readconf.c 2006-05-17 12:59:03.000000000 +0100 | |
513 | @@ -202,6 +202,9 @@ | |
514 | { "dns_ipv4_lookup", opt_stringptr, &dns_ipv4_lookup }, | |
515 | { "dns_retrans", opt_time, &dns_retrans }, | |
516 | { "dns_retry", opt_int, &dns_retry }, | |
517 | +#ifdef SUPPORT_DSN | |
518 | + { "dsn", opt_bool, &dsn }, | |
519 | +#endif | |
520 | /* This option is now a no-op, retained for compability */ | |
521 | { "drop_cr", opt_bool, &drop_cr }, | |
522 | /*********************************************************/ | |
523 | diff -urN exim-4.62-orig/src/receive.c exim-4.62-dsn/src/receive.c | |
524 | --- exim-4.62-orig/src/receive.c 2006-04-28 11:32:22.000000000 +0100 | |
525 | +++ exim-4.62-dsn/src/receive.c 2006-05-17 12:59:03.000000000 +0100 | |
526 | @@ -474,6 +474,8 @@ | |
527 | memcpy(recipients_list, oldlist, oldmax * sizeof(recipient_item)); | |
528 | } | |
529 | ||
530 | +/* memset added by GC to blank dsn records, etc. */ | |
531 | +memset(&recipients_list[recipients_count], 0, sizeof(recipient_item)); | |
532 | recipients_list[recipients_count].address = recipient; | |
533 | recipients_list[recipients_count].pno = pno; | |
534 | #ifdef EXPERIMENTAL_BRIGHTMAIL | |
535 | diff -urN exim-4.62-orig/src/route.c exim-4.62-dsn/src/route.c | |
536 | --- exim-4.62-orig/src/route.c 2006-04-28 11:32:22.000000000 +0100 | |
537 | +++ exim-4.62-dsn/src/route.c 2006-05-17 12:59:03.000000000 +0100 | |
538 | @@ -60,6 +60,10 @@ | |
539 | (void *)offsetof(router_instance, domains) }, | |
540 | { "driver", opt_stringptr|opt_public, | |
541 | (void *)offsetof(router_instance, driver_name) }, | |
542 | + #ifdef SUPPORT_DSN | |
543 | + { "dsn_process", opt_bool|opt_public, | |
544 | + (void *)offsetof(router_instance, dsn_process) }, | |
545 | + #endif | |
546 | { "errors_to", opt_stringptr|opt_public, | |
547 | (void *)(offsetof(router_instance, errors_to)) }, | |
548 | { "expn", opt_bool|opt_public, | |
549 | @@ -272,6 +276,13 @@ | |
550 | ||
551 | if (r->pass_router_name != NULL) | |
552 | set_router(r, r->pass_router_name, &(r->pass_router), TRUE); | |
553 | + | |
554 | + #ifdef SUPPORT_DSN | |
555 | + if (r->dsn_process == FALSE) | |
556 | + DEBUG(D_route) debug_printf("%s router skipping DSN - add dsn_process to router\n", r->name); | |
557 | + if (r->dsn_process == TRUE) | |
558 | + DEBUG(D_route) debug_printf("%s router performing DSN \n", r->name); | |
559 | + #endif | |
560 | } | |
561 | } | |
562 | ||
563 | @@ -1391,7 +1402,10 @@ | |
564 | ||
565 | copyflag(new, addr, af_propagate); | |
566 | new->p.address_data = addr->p.address_data; | |
567 | - | |
568 | +#ifdef SUPPORT_DSN | |
569 | + new->dsn_flags = addr->dsn_flags; | |
570 | + new->dsn_orcpt = addr->dsn_orcpt; | |
571 | +#endif | |
572 | ||
573 | /* As it has turned out, we haven't set headers_add or headers_remove for the | |
574 | * clone. Thinking about it, it isn't entirely clear whether they should be | |
575 | diff -urN exim-4.62-orig/src/smtp_in.c exim-4.62-dsn/src/smtp_in.c | |
576 | --- exim-4.62-orig/src/smtp_in.c 2006-04-28 11:32:23.000000000 +0100 | |
577 | +++ exim-4.62-dsn/src/smtp_in.c 2006-05-17 13:02:48.000000000 +0100 | |
578 | @@ -832,6 +832,13 @@ | |
579 | sender_verified_list = NULL; /* No senders verified */ | |
580 | memset(sender_address_cache, 0, sizeof(sender_address_cache)); | |
581 | memset(sender_domain_cache, 0, sizeof(sender_domain_cache)); | |
582 | + | |
583 | +#ifdef SUPPORT_DSN | |
584 | +/* Reset the DSN flags */ | |
585 | +dsn_ret = 0; | |
586 | +dsn_envid = NULL; | |
587 | +#endif | |
588 | + | |
589 | authenticated_sender = NULL; | |
590 | #ifdef EXPERIMENTAL_BRIGHTMAIL | |
591 | bmi_run = 0; | |
592 | @@ -2169,6 +2176,10 @@ | |
593 | int ptr, size, rc; | |
594 | int c, i; | |
595 | auth_instance *au; | |
596 | +#ifdef SUPPORT_DSN | |
597 | + uschar *orcpt = NULL; | |
598 | + int flags; | |
599 | +#endif | |
600 | ||
601 | switch(smtp_read_command(TRUE)) | |
602 | { | |
603 | @@ -2572,6 +2583,12 @@ | |
604 | if (accept_8bitmime) | |
605 | s = string_cat(s, &size, &ptr, US"250-8BITMIME\r\n", 14); | |
606 | ||
607 | + #ifdef SUPPORT_DSN | |
608 | + /* Advertise DSN support if configured to do so. */ | |
609 | + if (dsn) | |
610 | + s = string_cat(s, &size, &ptr, US"250-DSN\r\n", 9); | |
611 | + #endif | |
612 | + | |
613 | /* Advertise ETRN if there's an ACL checking whether a host is | |
614 | permitted to issue it; a check is made when any host actually tries. */ | |
615 | ||
616 | @@ -2763,6 +2780,43 @@ | |
617 | (strcmpic(value, US"8BITMIME") == 0 || | |
618 | strcmpic(value, US"7BIT") == 0)) {} | |
619 | ||
620 | + #ifdef SUPPORT_DSN | |
621 | + | |
622 | + /* Handle the two DSN options, but only if configured to do so (which | |
623 | + will have caused "DSN" to be given in the EHLO response). The code itself | |
624 | + is included only if configured in at build time. */ | |
625 | + | |
626 | + else if (dsn && strcmpic(name, US"RET") == 0) | |
627 | + { | |
628 | + /* Check if RET has already been set */ | |
629 | + if (dsn_ret > 0) { | |
630 | + synprot_error(L_smtp_syntax_error, 501, NULL, | |
631 | + US"RET can be specified once only"); | |
632 | + goto COMMAND_LOOP; | |
633 | + } | |
634 | + dsn_ret = (strcmpic(value, US"HDRS") == 0)? dsn_ret_hdrs : | |
635 | + (strcmpic(value, US"FULL") == 0)? dsn_ret_full : 0; | |
636 | + DEBUG(D_receive) debug_printf("DSN_RET: %d\n", dsn_ret); | |
637 | + /* Check for invalid invalid value, and exit with error */ | |
638 | + if (dsn_ret == 0) { | |
639 | + synprot_error(L_smtp_syntax_error, 501, NULL, | |
640 | + US"Value for RET is invalid"); | |
641 | + goto COMMAND_LOOP; | |
642 | + } | |
643 | + } | |
644 | + else if (dsn && strcmpic(name, US"ENVID") == 0) | |
645 | + { | |
646 | + /* Check if the dsn envid has been already set */ | |
647 | + if (dsn_envid != NULL) { | |
648 | + synprot_error(L_smtp_syntax_error, 501, NULL, | |
649 | + US"ENVID can be specified once only"); | |
650 | + goto COMMAND_LOOP; | |
651 | + } | |
652 | + dsn_envid = string_copy(value); | |
653 | + DEBUG(D_receive) debug_printf("DSN_ENVID: %s\n", dsn_envid); | |
654 | + } | |
655 | + #endif | |
656 | + | |
657 | /* Handle the AUTH extension. If the value given is not "<>" and either | |
658 | the ACL says "yes" or there is no ACL but the sending host is | |
659 | authenticated, we set it up as the authenticated sender. However, if the | |
660 | @@ -3010,6 +3064,89 @@ | |
661 | rcpt_fail_count++; | |
662 | break; | |
663 | } | |
664 | + | |
665 | + #ifdef SUPPORT_DSN | |
666 | + /* Set the DSN flags orcpt and dsn_flags from the session*/ | |
667 | + orcpt = NULL; | |
668 | + flags = 0; | |
669 | + | |
670 | + if (esmtp) for(;;) | |
671 | + { | |
672 | + uschar *name, *value, *end; | |
673 | + int size; | |
674 | + | |
675 | + if (!extract_option(&name, &value)) | |
676 | + { | |
677 | + break; | |
678 | + } | |
679 | + | |
680 | + if (strcmpic(name, US"ORCPT") == 0) | |
681 | + { | |
682 | + /* Check whether orcpt has been already set */ | |
683 | + if (orcpt != NULL) { | |
684 | + synprot_error(L_smtp_syntax_error, 501, NULL, | |
685 | + US"ORCPT can be specified once only"); | |
686 | + goto COMMAND_LOOP; | |
687 | + } | |
688 | + orcpt = string_copy(value); | |
689 | + DEBUG(D_receive) debug_printf("DSN orcpt: %s\n", orcpt); | |
690 | + } | |
691 | + | |
692 | + else if (strcmpic(name, US"NOTIFY") == 0) | |
693 | + { | |
694 | + /* Check if the notify flags have been already set */ | |
695 | + if (flags > 0) | |
696 | + { | |
697 | + synprot_error(L_smtp_syntax_error, 501, NULL, | |
698 | + US"NOTIFY can be specified once only"); | |
699 | + goto COMMAND_LOOP; | |
700 | + } | |
701 | + if (strcmpic(value, US"NEVER") == 0) flags |= rf_notify_never; else | |
702 | + { | |
703 | + uschar *p = value; | |
704 | + while (*p != 0) | |
705 | + { | |
706 | + uschar *pp = p; | |
707 | + while (*pp != 0 && *pp != ',') pp++; | |
708 | + if (*pp == ',') *pp++ = 0; | |
709 | + if (strcmpic(p, US"SUCCESS") == 0) { | |
710 | + DEBUG(D_receive) debug_printf("GC: Setting notify success\n"); | |
711 | + flags |= rf_notify_success; | |
712 | + } | |
713 | + else if (strcmpic(p, US"FAILURE") == 0) { | |
714 | + DEBUG(D_receive) debug_printf("GC: Setting notify failure\n"); | |
715 | + flags |= rf_notify_failure; | |
716 | + } | |
717 | + else if (strcmpic(p, US"DELAY") == 0) { | |
718 | + DEBUG(D_receive) debug_printf("GC: Setting notify delay\n"); | |
719 | + flags |= rf_notify_delay; | |
720 | + } | |
721 | + else | |
722 | + { | |
723 | + /* Catch any strange values */ | |
724 | + synprot_error(L_smtp_syntax_error, 501, NULL, | |
725 | + US"Invalid value for NOTIFY parameter"); | |
726 | + goto COMMAND_LOOP; | |
727 | + } | |
728 | + p = pp; | |
729 | + } | |
730 | + DEBUG(D_receive) debug_printf("DSN Flags: %x\n", flags); | |
731 | + } | |
732 | + } | |
733 | + | |
734 | + /* Unknown option. Stick back the terminator characters and break | |
735 | + the loop. An error for a malformed address will occur. */ | |
736 | + | |
737 | + else | |
738 | + { | |
739 | + DEBUG(D_receive) debug_printf("Invalid dsn command: %s : %s\n", name, value); | |
740 | + name[-1] = ' '; | |
741 | + value[-1] = '='; | |
742 | + break; | |
743 | + } | |
744 | + } | |
745 | + #endif | |
746 | + | |
747 | ||
748 | /* Apply SMTP rewriting then extract the working address. Don't allow "<>" | |
749 | as a recipient address */ | |
750 | @@ -3116,6 +3253,24 @@ | |
751 | { | |
752 | smtp_printf("250 Accepted\r\n"); | |
753 | receive_add_recipient(recipient, -1); | |
754 | + | |
755 | + #ifdef SUPPORT_DSN | |
756 | + | |
757 | + /* Set the dsn flags in the recipients_list */ | |
758 | + if (orcpt != NULL) | |
759 | + recipients_list[recipients_count-1].orcpt = orcpt; | |
760 | + else | |
761 | + recipients_list[recipients_count-1].orcpt = NULL; | |
762 | + | |
763 | + if (flags != 0) | |
764 | + recipients_list[recipients_count-1].dsn_flags = flags; | |
765 | + else | |
766 | + recipients_list[recipients_count-1].dsn_flags = 0; | |
767 | + debug_printf("DSN-AJ(smtp-in): orcpt: %s flags: %d\n", recipients_list[recipients_count-1].orcpt, recipients_list[recipients_count-1].dsn_flags); | |
768 | + | |
769 | + | |
770 | + #endif | |
771 | + | |
772 | } | |
773 | ||
774 | /* The recipient was discarded */ | |
775 | diff -urN exim-4.62-orig/src/spool_in.c exim-4.62-dsn/src/spool_in.c | |
776 | --- exim-4.62-orig/src/spool_in.c 2006-04-28 11:32:23.000000000 +0100 | |
777 | +++ exim-4.62-dsn/src/spool_in.c 2006-05-17 12:59:03.000000000 +0100 | |
778 | @@ -292,6 +292,13 @@ | |
779 | spam_score_int = NULL; | |
780 | #endif | |
781 | ||
782 | +#ifdef SUPPORT_DSN | |
783 | +#ifndef COMPILE_UTILITY | |
784 | +dsn_ret = 0; | |
785 | +dsn_envid = NULL; | |
786 | +#endif /* COMPILE_UTILITY */ | |
787 | +#endif | |
788 | + | |
789 | /* Generate the full name and open the file. If message_subdir is already | |
790 | set, just look in the given directory. Otherwise, look in both the split | |
791 | and unsplit directories, as for the data file above. */ | |
792 | @@ -474,6 +481,21 @@ | |
793 | tls_peerdn = string_copy(big_buffer + 12); | |
794 | #endif | |
795 | ||
796 | + #ifdef SUPPORT_DSN | |
797 | + #ifndef COMPILE_UTILITY | |
798 | + /* Check if the dsn flags have been set in the header file */ | |
799 | + else if (Ustrncmp(big_buffer, "-dsn_ret", 8) == 0) | |
800 | + { | |
801 | + dsn_ret= atoi(big_buffer + 8); | |
802 | + } | |
803 | + else if (Ustrncmp(big_buffer, "-dsn_envid", 10) == 0) | |
804 | + { | |
805 | + dsn_envid = string_copy(big_buffer + 11); | |
806 | + } | |
807 | + #endif /* COMPILE_UTILITY */ | |
808 | + #endif | |
809 | + | |
810 | + | |
811 | /* We now record the port number after the address, separated by a | |
812 | dot. For compatibility during upgrading, do nothing if there | |
813 | isn't a value (it gets left at zero). */ | |
814 | @@ -558,6 +580,10 @@ | |
815 | { | |
816 | int nn; | |
817 | int pno = -1; | |
818 | + #ifdef SUPPORT_DSN | |
819 | + int dsn_flags = 0; | |
820 | + uschar *orcpt = NULL; | |
821 | + #endif | |
822 | uschar *errors_to = NULL; | |
823 | uschar *p; | |
824 | ||
825 | @@ -626,10 +652,19 @@ | |
826 | } | |
827 | ||
828 | /* Handle current format Exim 4 spool files */ | |
829 | + /* Spool file is modified if DSN is supported | |
830 | + Original was "address errors_to len(errors_to),pno | |
831 | + New for DSN support is now: | |
832 | + "address errors_to orcpt len(errors_to),len(orcpt),pno,dsn_flags */ | |
833 | ||
834 | else if (*p == '#') | |
835 | { | |
836 | int flags; | |
837 | + | |
838 | + #ifndef COMPILE_UTILITY | |
839 | + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - Exim 4 standard format spoolfile\n"); | |
840 | + #endif /* COMPILE_UTILITY */ | |
841 | + | |
842 | (void)sscanf(CS p+1, "%d", &flags); | |
843 | ||
844 | if ((flags & 0x01) != 0) /* one_time data exists */ | |
845 | @@ -642,15 +677,82 @@ | |
846 | { | |
847 | p -= len; | |
848 | errors_to = string_copy(p); | |
849 | + } | |
850 | + } | |
851 | + | |
852 | + *(--p) = 0; /* Terminate address */ | |
853 | + } | |
854 | + #ifdef SUPPORT_DSN | |
855 | + else if (*p == '!') /* Handle Exim4 + DSN spool files */ | |
856 | + { | |
857 | + int flags; | |
858 | + int temp_dsn_flags; | |
859 | + | |
860 | + #ifndef COMPILE_UTILITY | |
861 | + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - C&W DSN format spoolfile\n"); | |
862 | + #endif /* COMPILE_UTILITY */ | |
863 | + | |
864 | + sscanf(CS p+1, "%d,%d", &flags, &temp_dsn_flags); | |
865 | + | |
866 | + if (((flags & 0x01) != 0) || (temp_dsn_flags > 0)) /* one_time data or dsn_flags exist */ | |
867 | + { | |
868 | + int len; | |
869 | + int len_orcpt; | |
870 | + | |
871 | + #ifndef COMPILE_UTILITY | |
872 | + DEBUG(D_deliver) debug_printf("**** spool_in dsn_flags = 0\n"); | |
873 | + #endif /* COMPILE_UTILITY */ | |
874 | + | |
875 | + dsn_flags = 0; | |
876 | + | |
877 | + while (isdigit(*(--p)) || *p == ',' || *p == '-'); | |
878 | + sscanf(CS p+1, "%d,%d,%d,%d", &len, &len_orcpt, &pno, &dsn_flags); | |
879 | + | |
880 | + *p = 0; | |
881 | + if (len_orcpt > 0) | |
882 | + { | |
883 | + p -= len_orcpt; | |
884 | + orcpt = string_copy(p); | |
885 | } | |
886 | + *(--p) = 0; /* change the space to a NULL */ | |
887 | + | |
888 | + if (len > 0) | |
889 | + { | |
890 | + p -= len; | |
891 | + errors_to = string_copy(p); | |
892 | + } | |
893 | } | |
894 | ||
895 | *(--p) = 0; /* Terminate address */ | |
896 | } | |
897 | + #endif | |
898 | + #ifndef COMPILE_UTILITY | |
899 | + else | |
900 | + { | |
901 | + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - No additional fields\n"); | |
902 | + } | |
903 | + #endif /* COMPILE_UTILITY */ | |
904 | + | |
905 | + #ifdef SUPPORT_DSN | |
906 | + #ifndef COMPILE_UTILITY | |
907 | + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n", | |
908 | + big_buffer, errors_to, orcpt, dsn_flags); | |
909 | + #endif /* COMPILE_UTILITY */ | |
910 | + #endif | |
911 | + #ifndef SUPPORT_DSN | |
912 | + #ifndef COMPILE_UTILITY | |
913 | + DEBUG(D_deliver) debug_printf("**** SPOOL_IN - address: |%s| errorsto: |%s|\n", | |
914 | + big_buffer, errors_to); | |
915 | + #endif /* COMPILE_UTILITY */ | |
916 | + #endif | |
917 | ||
918 | recipients_list[recipients_count].address = string_copy(big_buffer); | |
919 | recipients_list[recipients_count].pno = pno; | |
920 | recipients_list[recipients_count].errors_to = errors_to; | |
921 | + #ifdef SUPPORT_DSN | |
922 | + recipients_list[recipients_count].orcpt = orcpt; | |
923 | + recipients_list[recipients_count].dsn_flags = dsn_flags; | |
924 | + #endif | |
925 | } | |
926 | ||
927 | /* The remainder of the spool header file contains the headers for the message, | |
928 | diff -urN exim-4.62-orig/src/spool_out.c exim-4.62-dsn/src/spool_out.c | |
929 | --- exim-4.62-orig/src/spool_out.c 2006-04-28 11:32:23.000000000 +0100 | |
930 | +++ exim-4.62-dsn/src/spool_out.c 2006-05-17 12:59:03.000000000 +0100 | |
931 | @@ -243,6 +243,15 @@ | |
932 | if (tls_peerdn != NULL) fprintf(f, "-tls_peerdn %s\n", tls_peerdn); | |
933 | #endif | |
934 | ||
935 | +#ifdef SUPPORT_DSN | |
936 | +/* Write the dsn flags to the spool header file */ | |
937 | +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_envid %s\n", dsn_envid); | |
938 | +if (dsn_envid != NULL) fprintf(f, "-dsn_envid %s\n", dsn_envid); | |
939 | +DEBUG(D_deliver) debug_printf("DSN: Write SPOOL :-dsn_ret %d\n", dsn_ret); | |
940 | +if (dsn_ret != 0) fprintf(f, "-dsn_ret %d\n", dsn_ret); | |
941 | +#endif | |
942 | + | |
943 | + | |
944 | /* To complete the envelope, write out the tree of non-recipients, followed by | |
945 | the list of recipients. These won't be disjoint the first time, when no | |
946 | checking has been done. If a recipient is a "one-time" alias, it is followed by | |
947 | @@ -253,14 +262,36 @@ | |
948 | for (i = 0; i < recipients_count; i++) | |
949 | { | |
950 | recipient_item *r = recipients_list + i; | |
951 | - if (r->pno < 0 && r->errors_to == NULL) | |
952 | +#ifdef SUPPORT_DSN | |
953 | +DEBUG(D_deliver) debug_printf("DSN: Flags :%d\n", r->dsn_flags); | |
954 | +#endif | |
955 | + if (r->pno < 0 && r->errors_to == NULL | |
956 | + #ifdef SUPPORT_DSN | |
957 | + && r->dsn_flags == 0 | |
958 | + #endif | |
959 | + ) | |
960 | fprintf(f, "%s\n", r->address); | |
961 | else | |
962 | { | |
963 | uschar *errors_to = (r->errors_to == NULL)? US"" : r->errors_to; | |
964 | + #ifdef SUPPORT_DSN | |
965 | + uschar *orcpt = (r->orcpt == NULL)? US"" : r->orcpt; | |
966 | + fprintf(f, "%s %s %s %d,%d,%d,%d!1\n", r->address, errors_to, orcpt, | |
967 | + Ustrlen(errors_to), Ustrlen(orcpt), r->pno, r->dsn_flags); | |
968 | + #else | |
969 | fprintf(f, "%s %s %d,%d#1\n", r->address, errors_to, | |
970 | Ustrlen(errors_to), r->pno); | |
971 | + #endif | |
972 | } | |
973 | + | |
974 | + #ifdef SUPPORT_DSN | |
975 | + DEBUG(D_deliver) debug_printf("DSN :**** SPOOL_OUT - address: |%s| errorsto: |%s| orcpt: |%s| dsn_flags: %d\n", | |
976 | + r->address, r->errors_to, r->orcpt, r->dsn_flags); | |
977 | + #endif | |
978 | + #ifndef SUPPORT_DSN | |
979 | + DEBUG(D_deliver) debug_printf("**** SPOOL_OUT - address: |%s| errorsto: |%s|\n", | |
980 | + r->address, r->errors_to); | |
981 | + #endif | |
982 | } | |
983 | ||
984 | /* Put a blank line before the headers */ | |
985 | diff -urN exim-4.62-orig/src/structs.h exim-4.62-dsn/src/structs.h | |
986 | --- exim-4.62-orig/src/structs.h 2006-04-28 11:32:23.000000000 +0100 | |
987 | +++ exim-4.62-dsn/src/structs.h 2006-05-17 12:59:03.000000000 +0100 | |
988 | @@ -281,7 +281,9 @@ | |
989 | BOOL verify_sender; /* Use this router when verifying a sender */ | |
990 | BOOL uid_set; /* Flag to indicate uid is set */ | |
991 | BOOL unseen; /* If TRUE carry on, even after success */ | |
992 | - | |
993 | +#ifdef SUPPORT_DSN | |
994 | + BOOL dsn_process; /* If TRUE, activate DSN for this router */ | |
995 | +#endif | |
996 | int self_code; /* Encoded version of "self" */ | |
997 | uid_t uid; /* Fixed uid value */ | |
998 | gid_t gid; /* Fixed gid value */ | |
999 | @@ -560,6 +562,12 @@ | |
1000 | uschar *peerdn; /* DN of server's certificate */ | |
1001 | #endif | |
1002 | ||
1003 | + #ifdef SUPPORT_DSN | |
1004 | + uschar *dsn_orcpt; /* DSN orcpt value */ | |
1005 | + int dsn_flags; /* DSN flags */ | |
1006 | + uschar *dsn_aware; /* DSN aware flag */ | |
1007 | + #endif | |
1008 | + | |
1009 | uid_t uid; /* uid for transporting */ | |
1010 | gid_t gid; /* gid for transporting */ | |
1011 | ||
1012 | diff -urN exim-4.62-orig/src/transport.c exim-4.62-dsn/src/transport.c | |
1013 | --- exim-4.62-orig/src/transport.c 2006-04-28 11:32:23.000000000 +0100 | |
1014 | +++ exim-4.62-dsn/src/transport.c 2006-05-17 12:59:03.000000000 +0100 | |
1015 | @@ -1756,6 +1756,11 @@ | |
1016 | ||
1017 | argv = child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0); | |
1018 | ||
1019 | + #ifdef SUPPORT_DSN | |
1020 | + /* Call with the dsn flag */ | |
1021 | + if (smtp_use_dsn) argv[i++] = US"-MCD"; | |
1022 | + #endif | |
1023 | + | |
1024 | if (smtp_authenticated) argv[i++] = US"-MCA"; | |
1025 | ||
1026 | #ifdef SUPPORT_TLS | |
1027 | diff -urN exim-4.62-orig/src/transports/smtp.c exim-4.62-dsn/src/transports/smtp.c | |
1028 | --- exim-4.62-orig/src/transports/smtp.c 2006-04-28 11:32:23.000000000 +0100 | |
1029 | +++ exim-4.62-dsn/src/transports/smtp.c 2006-05-17 12:59:03.000000000 +0100 | |
1030 | @@ -194,6 +194,16 @@ | |
1031 | static uschar *smtp_command; /* Points to last cmd for error messages */ | |
1032 | static uschar *mail_command; /* Points to MAIL cmd for error messages */ | |
1033 | ||
1034 | +#ifdef SUPPORT_DSN | |
1035 | +/* some DSN flags for use later */ | |
1036 | + | |
1037 | +static int rf_list[] = {rf_notify_never, rf_notify_success, | |
1038 | + rf_notify_failure, rf_notify_delay }; | |
1039 | + | |
1040 | +static uschar *rf_names[] = { "NEVER", "SUCCESS", "FAILURE", "DELAY" }; | |
1041 | +#endif | |
1042 | + | |
1043 | + | |
1044 | ||
1045 | /************************************************* | |
1046 | * Setup entry point * | |
1047 | @@ -1137,6 +1147,14 @@ | |
1048 | DEBUG(D_transport) debug_printf("%susing PIPELINING\n", | |
1049 | smtp_use_pipelining? "" : "not "); | |
1050 | ||
1051 | + #ifdef SUPPORT_DSN | |
1052 | + /* Note if the server supports DSN */ | |
1053 | + smtp_use_dsn = dsn && | |
1054 | + esmtp && pcre_exec(regex_DSN, NULL, CS buffer, (int)Ustrlen(CS buffer), 0, | |
1055 | + PCRE_EOPT, NULL, 0) >= 0; | |
1056 | + DEBUG(D_transport) debug_printf("use_dsn=%d\n", smtp_use_dsn); | |
1057 | + #endif | |
1058 | + | |
1059 | /* Note if the response to EHLO specifies support for the AUTH extension. | |
1060 | If it has, check that this host is one we want to authenticate to, and do | |
1061 | the business. The host name and address must be available when the | |
1062 | @@ -1324,6 +1342,26 @@ | |
1063 | while (*p) p++; | |
1064 | } | |
1065 | ||
1066 | +#ifdef SUPPORT_DSN | |
1067 | +/* Add any DSN flags to the mail command */ | |
1068 | + | |
1069 | +if (smtp_use_dsn) | |
1070 | + { | |
1071 | + if (dsn_ret == dsn_ret_hdrs) | |
1072 | + { | |
1073 | + strcpy(p, " RET=HDRS"); | |
1074 | + while (*p) p++; | |
1075 | + } | |
1076 | + else if (dsn_ret == dsn_ret_full) | |
1077 | + { | |
1078 | + strcpy(p, " RET=FULL"); | |
1079 | + while (*p) p++; | |
1080 | + } | |
1081 | + if (dsn_envid != NULL) | |
1082 | + string_format(p, sizeof(buffer) - (p-buffer), " ENVID=%s", dsn_envid); | |
1083 | + } | |
1084 | +#endif | |
1085 | + | |
1086 | /* Add the authenticated sender address if present */ | |
1087 | ||
1088 | if ((smtp_authenticated || ob->authenticated_sender_force) && | |
1089 | @@ -1386,18 +1424,66 @@ | |
1090 | int count; | |
1091 | BOOL no_flush; | |
1092 | ||
1093 | + #ifdef SUPPORT_DSN | |
1094 | + /* philb - set dsn_aware flag for this recipient */ | |
1095 | + if(smtp_use_dsn) | |
1096 | + addr->dsn_aware = string_copy("Y"); | |
1097 | + else | |
1098 | + addr->dsn_aware = string_copy("N"); | |
1099 | + #endif | |
1100 | + | |
1101 | if (addr->transport_return != PENDING_DEFER) continue; | |
1102 | ||
1103 | address_count++; | |
1104 | no_flush = smtp_use_pipelining && (!mua_wrapper || addr->next != NULL); | |
1105 | ||
1106 | + #ifdef SUPPORT_DSN | |
1107 | + /* Add any DSN flags to the rcpt command and add to the sent string */ | |
1108 | + | |
1109 | + p = buffer; | |
1110 | + *p = 0; | |
1111 | + | |
1112 | + if (smtp_use_dsn) | |
1113 | + { | |
1114 | + if ((addr->dsn_flags & rf_dsnflags) != 0) | |
1115 | + { | |
1116 | + int i; | |
1117 | + BOOL first = TRUE; | |
1118 | + strcpy(p, " NOTIFY="); | |
1119 | + while (*p) p++; | |
1120 | + for (i = 0; i < 4; i++) | |
1121 | + { | |
1122 | + if ((addr->dsn_flags & rf_list[i]) != 0) | |
1123 | + { | |
1124 | + if (!first) *p++ = ','; | |
1125 | + first = FALSE; | |
1126 | + strcpy(p, rf_names[i]); | |
1127 | + while (*p) p++; | |
1128 | + } | |
1129 | + } | |
1130 | + } | |
1131 | + | |
1132 | + if (addr->dsn_orcpt != NULL) | |
1133 | + string_format(p, sizeof(buffer) - (p-buffer), " ORCPT=%s", | |
1134 | + addr->dsn_orcpt); | |
1135 | + } | |
1136 | + | |
1137 | + #endif | |
1138 | + | |
1139 | + | |
1140 | /* Now send the RCPT command, and process outstanding responses when | |
1141 | necessary. After a timeout on RCPT, we just end the function, leaving the | |
1142 | yield as OK, because this error can often mean that there is a problem with | |
1143 | just one address, so we don't want to delay the host. */ | |
1144 | ||
1145 | + #ifdef SUPPORT_DSN | |
1146 | + count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s%s\r\n", | |
1147 | + transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr, buffer); | |
1148 | + #else | |
1149 | count = smtp_write_command(&outblock, no_flush, "RCPT TO:<%s>%s\r\n", | |
1150 | transport_rcpt_address(addr, tblock->rcpt_include_affixes), igquotstr); | |
1151 | + #endif | |
1152 | + | |
1153 | if (count < 0) goto SEND_FAILED; | |
1154 | if (count > 0) | |
1155 | { | |
1156 |