]> git.pld-linux.org Git - packages/exim.git/blame - exim_462_dsn_1_2.patch
- rel 3; increase spam timeout to 15s
[packages/exim.git] / exim_462_dsn_1_2.patch
CommitLineData
e859f219
AM
1diff -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
109diff -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
120diff -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
373diff -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
403diff -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;
450diff -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. */
467diff -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;
484diff -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
510diff -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 /*********************************************************/
523diff -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
535diff -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
575diff -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 */
775diff -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,
928diff -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 */
985diff -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
1012diff -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
1027diff -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
This page took 0.295106 seconds and 4 git commands to generate.