static address_item *addr_remote = NULL;
static address_item *addr_route = NULL;
static address_item *addr_succeed = NULL;
-static address_item *addr_dsntmp = NULL;
static address_item *addr_senddsn = NULL;
static FILE *message_log = NULL;
static ssize_t
readn(int fd, void * buffer, size_t len)
{
- void * next = buffer;
- void * end = buffer + len;
+uschar * next = buffer;
+uschar * end = next + len;
- while (next < end)
- {
- ssize_t got = read(fd, next, end - next);
+while (next < end)
+ {
+ ssize_t got = read(fd, next, end - next);
- /* I'm not sure if there are signals that can interrupt us,
- for now I assume the worst */
- if (got == -1 && errno == EINTR) continue;
- if (got <= 0) return next - buffer;
- next += got;
- }
+ /* I'm not sure if there are signals that can interrupt us,
+ for now I assume the worst */
+ if (got == -1 && errno == EINTR) continue;
+ if (got <= 0) return next - US buffer;
+ next += got;
+ }
- return len;
+return len;
}
address_item *
deliver_make_addr(uschar *address, BOOL copy)
{
-address_item *addr = store_get(sizeof(address_item));
+address_item *addr = store_get(sizeof(address_item), FALSE);
*addr = address_defaults;
if (copy) address = string_copy(address);
addr->address = address;
deliver_address_data = addr->prop.address_data;
deliver_domain_data = addr->prop.domain_data;
deliver_localpart_data = addr->prop.localpart_data;
+router_var = addr->prop.variables;
/* These may be unset for multiple addresses */
static int
open_msglog_file(uschar *filename, int mode, uschar **error)
{
+if (Ustrstr(filename, US"/../"))
+ log_write(0, LOG_MAIN|LOG_PANIC,
+ "Attempt to open msglog file path with upward-traversal: '%s'\n", filename);
+
for (int i = 2; i > 0; i--)
{
int fd = Uopen(filename,
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
static gstring *
-d_tlslog(gstring * s, address_item * addr)
+d_tlslog(gstring * g, address_item * addr)
{
if (LOGGING(tls_cipher) && addr->cipher)
- s = string_append(s, 2, US" X=", addr->cipher);
+ {
+ g = string_append(g, 2, US" X=", addr->cipher);
+#ifdef EXPERIMENTAL_TLS_RESUME
+ if (LOGGING(tls_resumption) && testflag(addr, af_tls_resume))
+ g = string_catn(g, US"*", 1);
+#endif
+ }
if (LOGGING(tls_certificate_verified) && addr->cipher)
- s = string_append(s, 2, US" CV=",
+ g = string_append(g, 2, US" CV=",
testflag(addr, af_cert_verified)
?
#ifdef SUPPORT_DANE
"yes"
: "no");
if (LOGGING(tls_peerdn) && addr->peerdn)
- s = string_append(s, 3, US" DN=\"", string_printing(addr->peerdn), US"\"");
-return s;
+ g = string_append(g, 3, US" DN=\"", string_printing(addr->peerdn), US"\"");
+return g;
}
#endif
else
{
- uschar * cmp = g->s + g->ptr;
+ uschar * cmp;
+ int off = g->ptr; /* start of the "full address" */
if (addr->local_part)
{
of all, do a caseless comparison; if this succeeds, do a caseful comparison
on the local parts. */
+ cmp = g->s + off; /* only now, as rebuffer likely done */
string_from_gstring(g); /* ensure nul-terminated */
if ( strcmpic(cmp, topaddr->address) == 0
&& Ustrncmp(cmp, topaddr->address, Ustrchr(cmp, '@') - cmp) == 0
-void
-timesince(struct timeval * diff, struct timeval * then)
-{
-gettimeofday(diff, NULL);
-diff->tv_sec -= then->tv_sec;
-if ((diff->tv_usec -= then->tv_usec) < 0)
- {
- diff->tv_sec--;
- diff->tv_usec += 1000*1000;
- }
-}
-
-
-
-uschar *
-string_timediff(struct timeval * diff)
-{
-static uschar buf[sizeof("0.000s")];
-
-if (diff->tv_sec >= 5 || !LOGGING(millisec))
- return readconf_printtime((int)diff->tv_sec);
-
-sprintf(CS buf, "%u.%03us", (uint)diff->tv_sec, (uint)diff->tv_usec/1000);
-return buf;
-}
-
-
-uschar *
-string_timesince(struct timeval * then)
-{
-struct timeval diff;
-
-timesince(&diff, then);
-return string_timediff(&diff);
-}
-
/******************************************************************************/
delivery_log(int flags, address_item * addr, int logchar, uschar * msg)
{
gstring * g; /* Used for a temporary, expanding buffer, for building log lines */
-void * reset_point; /* released afterwards. */
+rmark reset_point;
/* Log the delivery on the main log. We use an extensible string to build up
the log line, and reset the store afterwards. Remote deliveries should always
lookup_dnssec_authenticated = NULL;
#endif
-g = reset_point = string_get(256);
+reset_point = store_mark();
+g = string_get_tainted(256, TRUE); /* addrs will be tainted, so avoid copy */
if (msg)
g = string_append(g, 2, host_and_ident(TRUE), US" ");
#endif
}
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
g = d_tlslog(g, addr);
#endif
{
if (testflag(addr, af_pipelining))
g = string_catn(g, US" L", 2);
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
if (testflag(addr, af_early_pipe))
g = string_catn(g, US"*", 1);
#endif
deferral_log(address_item * addr, uschar * now,
int logflags, uschar * driver_name, uschar * driver_kind)
{
-gstring * g;
-void * reset_point;
+rmark reset_point = store_mark();
+gstring * g = string_get(256);
/* Build up the line that is used for both the message log and the main
log. */
-g = reset_point = string_get(256);
-
/* Create the address string for logging. Must not do this earlier, because
an OK result may be changed to FAIL when a pipe returns text. */
static void
failure_log(address_item * addr, uschar * driver_kind, uschar * now)
{
-void * reset_point;
-gstring * g = reset_point = string_get(256);
+rmark reset_point = store_mark();
+gstring * g = string_get(256);
#ifndef DISABLE_EVENT
/* Message failures for which we will send a DSN get their event raised
if (addr->host_used)
g = d_hostlog(g, addr);
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
g = d_tlslog(g, addr);
#endif
}
/* Certificates for logging (via events) */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
tls_out.ourcert = addr->ourcert;
addr->ourcert = NULL;
tls_out.peercert = addr->peercert;
addr->peercert = NULL;
+ tls_out.ver = addr->tlsver;
tls_out.cipher = addr->cipher;
tls_out.peerdn = addr->peerdn;
tls_out.ocsp = addr->ocsp;
delivery_log(LOG_MAIN, addr, logchar, NULL);
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
tls_free_cert(&tls_out.ourcert);
tls_free_cert(&tls_out.peercert);
+ tls_out.ver = NULL;
tls_out.cipher = NULL;
tls_out.peerdn = NULL;
tls_out.ocsp = OCSP_NOT_REQ;
gstring * g;
va_start(ap, format);
- g = string_vformat(NULL, TRUE, CS format, ap);
+ g = string_vformat(NULL, SVFMT_EXTEND|SVFMT_REBUFFER, CS format, ap);
va_end(ap);
addr->message = string_from_gstring(g);
}
static BOOL
previously_transported(address_item *addr, BOOL testing)
{
-(void)string_format(big_buffer, big_buffer_size, "%s/%s",
+uschar * s = string_sprintf("%s/%s",
addr->unique + (testflag(addr, af_homonym)? 3:0), addr->transport->name);
-if (tree_search(tree_nonrecipients, big_buffer) != 0)
+if (tree_search(tree_nonrecipients, s) != 0)
{
DEBUG(D_deliver|D_route|D_transport)
debug_printf("%s was previously delivered (%s transport): discarded\n",
/* In the test harness, wait just a bit to let the subprocess finish off
any debug output etc first. */
- if (f.running_in_test_harness) millisleep(300);
+ testharness_pause_ms(300);
DEBUG(D_deliver) debug_printf("journalling %s", big_buffer);
len = Ustrlen(big_buffer);
f.disable_logging = FALSE; /* Jic */
addr->message = addr->router
? string_sprintf("No transport set by %s router", addr->router->name)
- : string_sprintf("No transport set by system filter");
+ : US"No transport set by system filter";
post_process_one(addr, DEFER, logflags, EXIM_DTYPE_TRANSPORT, 0);
continue;
}
of these checks, rather than for all local deliveries, because some local
deliveries (e.g. to pipes) can take a substantial time. */
- if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+ if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
{
DEBUG(D_deliver|D_retry|D_hints_lookup)
debug_printf("no retry data available\n");
else for (addr2 = addr; addr2; addr2 = addr2->next)
if (addr2->transport_return == OK)
{
- addr3 = store_get(sizeof(address_item));
+ addr3 = store_get(sizeof(address_item), FALSE);
*addr3 = *addr2;
addr3->next = NULL;
addr3->shadow_message = US &addr2->shadow_message;
if (!r || !(*ptr & rf_delete))
{
- r = store_get(sizeof(retry_item));
+ r = store_get(sizeof(retry_item), FALSE);
r->next = addr->retries;
addr->retries = r;
r->flags = *ptr++;
it in with the other info, in order to keep each message short enough to
guarantee it won't be split in the pipe. */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
case 'X':
if (!addr) goto ADDR_MISMATCH; /* Below, in 'A' handler */
switch (*subid)
{
case '1':
- addr->cipher = NULL;
- addr->peerdn = NULL;
+ addr->tlsver = addr->cipher = addr->peerdn = NULL;
if (*ptr)
+ {
addr->cipher = string_copy(ptr);
+ addr->tlsver = string_copyn(ptr, Ustrchr(ptr, ':') - ptr);
+ }
while (*ptr++);
if (*ptr)
addr->peerdn = string_copy(ptr);
}
while (*ptr++);
break;
-#endif /*SUPPORT_TLS*/
+#endif /*DISABLE_TLS*/
case 'C': /* client authenticator information */
switch (*subid)
case 'L':
switch (*subid)
{
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
case 2: setflag(addr, af_early_pipe); /*FALLTHROUGH*/
#endif
case 1: setflag(addr, af_pipelining); break;
if (*ptr)
{
- h = store_get(sizeof(host_item));
+ h = store_get(sizeof(host_item), FALSE);
h->name = string_copy(ptr);
while (*ptr++);
h->address = string_copy(ptr);
if (!parlist)
{
- parlist = store_get(remote_max_parallel * sizeof(pardata));
+ parlist = store_get(remote_max_parallel * sizeof(pardata), FALSE);
for (poffset = 0; poffset < remote_max_parallel; poffset++)
parlist[poffset].pid = 0;
}
for(; addr; addr = addr->next)
{
uschar *ptr;
- retry_item *r;
/* The certificate verification status goes into the flags */
if (tls_out.certificate_verified) setflag(addr, af_cert_verified);
#ifdef SUPPORT_DANE
if (tls_out.dane_verified) setflag(addr, af_dane_verified);
#endif
+# ifdef EXPERIMENTAL_TLS_RESUME
+ if (tls_out.resumption & RESUME_USED) setflag(addr, af_tls_resume);
+# endif
/* Use an X item only if there's something to send */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
if (addr->cipher)
{
ptr = big_buffer + sprintf(CS big_buffer, "%.128s", addr->cipher) + 1;
if (addr->peercert)
{
ptr = big_buffer;
- if (!tls_export_cert(ptr, big_buffer_size-2, addr->peercert))
+ if (tls_export_cert(ptr, big_buffer_size-2, addr->peercert))
while(*ptr++);
else
*ptr++ = 0;
if (addr->ourcert)
{
ptr = big_buffer;
- if (!tls_export_cert(ptr, big_buffer_size-2, addr->ourcert))
+ if (tls_export_cert(ptr, big_buffer_size-2, addr->ourcert))
while(*ptr++);
else
*ptr++ = 0;
rmt_dlv_checked_write(fd, 'X', '4', big_buffer, ptr - big_buffer);
}
# endif
-#endif /*SUPPORT_TLS*/
+#endif /*DISABLE_TLS*/
if (client_authenticator)
{
#endif
if (testflag(addr, af_pipelining))
-#ifdef EXPERIMENTAL_PIPE_CONNECT
+#ifndef DISABLE_PIPE_CONNECT
if (testflag(addr, af_early_pipe))
rmt_dlv_checked_write(fd, 'L', '2', NULL, 0);
else
/* Retry information: for most success cases this will be null. */
- for (r = addr->retries; r; r = r->next)
+ for (retry_item * r = addr->retries; r; r = r->next)
{
sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
if (cutthrough.cctx.sock >= 0 && cutthrough.callout_hold_only)
{
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
if (cutthrough.is_tls)
tls_close(cutthrough.cctx.tls_ctx, TLS_NO_SHUTDOWN);
#endif
/* Otherwise, if we are running in the test harness, wait a bit, to let the
newly created process get going before we create another process. This should
- ensure repeatability in the tests. We only need to wait a tad. */
+ ensure repeatability in the tests. Wait long enough for most cases to complete
+ the transport. */
- else if (f.running_in_test_harness) millisleep(500);
+ else testharness_pause_ms(600);
continue;
this, Jan 1999.] We know the syntax is valid, so this can be done by simply
removing quoting backslashes and any unquoted doublequotes. */
-t = addr->cc_local_part = store_get(len+1);
+t = addr->cc_local_part = store_get(len+1, is_tainted(address));
while(len-- > 0)
{
int c = *address++;
if (new_address)
{
- address_item *new_parent = store_get(sizeof(address_item));
+ address_item *new_parent = store_get(sizeof(address_item), FALSE);
*new_parent = *addr;
addr->parent = new_parent;
new_parent->child_count = 1;
+/************************************************/
+
+static void
+print_dsn_addr_action(FILE * f, address_item * addr,
+ uschar * action, uschar * status)
+{
+address_item * pa;
+
+if (addr->dsn_orcpt)
+ fprintf(f,"Original-Recipient: %s\n", addr->dsn_orcpt);
+
+for (pa = addr; pa->parent; ) pa = pa->parent;
+fprintf(f, "Action: %s\n"
+ "Final-Recipient: rfc822;%s\n"
+ "Status: %s\n",
+ action, pa->address, status);
+}
+
+
+
+/* When running in the test harness, there's an option that allows us to
+fudge this time so as to get repeatability of the tests. Take the first
+time off the list. In queue runs, the list pointer gets updated in the
+calling process. */
+
+int
+test_harness_fudged_queue_time(int actual_time)
+{
+int qt;
+if ( f.running_in_test_harness && *fudged_queue_times
+ && (qt = readconf_readtime(fudged_queue_times, '/', FALSE)) >= 0)
+ {
+ DEBUG(D_deliver) debug_printf("fudged queue_times = %s\n",
+ fudged_queue_times);
+ return qt;
+ }
+return actual_time;
+}
+
/*************************************************
* Deliver one message *
*************************************************/
open_db dbblock;
open_db *dbm_file;
extern int acl_where;
+uschar *info;
-uschar *info = queue_run_pid == (pid_t)0
+#ifdef MEASURE_TIMING
+report_time_since(×tamp_startup, US"delivery start"); /* testcase 0022, 2100 */
+#endif
+
+info = queue_run_pid == (pid_t)0
? string_sprintf("delivering %s", id)
: string_sprintf("delivering %s (queue run pid %d)", id, queue_run_pid);
if (addr_new)
{
- int uid = (system_filter_uid_set)? system_filter_uid : geteuid();
- int gid = (system_filter_gid_set)? system_filter_gid : getegid();
+ int uid = system_filter_uid_set ? system_filter_uid : geteuid();
+ int gid = system_filter_gid_set ? system_filter_gid : getegid();
/* The text "system-filter" is tested in transport_set_up_command() and in
set_up_shell_command() in the pipe transport, to enable them to permit
if (!tmp)
p->message = string_sprintf("failed to expand \"%s\" as a "
"system filter transport name", tpname);
+ if (is_tainted(tmp))
+ p->message = string_sprintf("attempt to used tainted value '%s' for"
+ "transport '%s' as a system filter", tmp, tpname);
tpname = tmp;
}
else
new->onetime_parent = recipients_list[r->pno].address;
/* If DSN support is enabled, set the dsn flags and the original receipt
- to be passed on to other DSN enabled MTAs */
+ to be passed on to other DSN enabled MTAs */
+
new->dsn_flags = r->dsn_flags & rf_dsnflags;
new->dsn_orcpt = r->orcpt;
- DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: %d\n",
+ DEBUG(D_deliver) debug_printf("DSN: set orcpt: %s flags: 0x%x\n",
new->dsn_orcpt ? new->dsn_orcpt : US"", new->dsn_flags);
switch (process_recipients)
}
#ifndef DISABLE_EVENT
- if (process_recipients != RECIP_ACCEPT)
+ if (process_recipients != RECIP_ACCEPT && event_action)
{
uschar * save_local = deliver_localpart;
const uschar * save_domain = deliver_domain;
/* Failure to open the retry database is treated the same as if it does
not exist. In both cases, dbm_file is NULL. */
- if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE)))
+ if (!(dbm_file = dbfn_open(US"retry", O_RDONLY, &dbblock, FALSE, TRUE)))
DEBUG(D_deliver|D_retry|D_route|D_hints_lookup)
debug_printf("no retry data available\n");
keep piling '>' characters on the front. */
if (addr->address[0] == '>')
- {
while (tree_search(tree_duplicates, addr->unique))
addr->unique = string_sprintf(">%s", addr->unique);
- }
else if ((tnode = tree_search(tree_duplicates, addr->unique)))
{
(void)post_process_one(addr, DEFER, LOG_MAIN, EXIM_DTYPE_ROUTER, 0);
/* For remote-retry errors (here and just above) that we've not yet
- hit the rery time, use the error recorded in the retry database
+ hit the retry time, use the error recorded in the retry database
as info in the warning message. This lets us send a message even
when we're not failing on a fresh attempt. We assume that this
info is not sensitive. */
&addr_succeed, v_none)) == DEFER)
retry_add_item(addr,
addr->router->retry_use_local_part
- ? string_sprintf("R:%s@%s", addr->local_part, addr->domain)
- : string_sprintf("R:%s", addr->domain),
+ ? string_sprintf("R:%s@%s", addr->local_part, addr->domain)
+ : string_sprintf("R:%s", addr->domain),
0);
/* Otherwise, if there is an existing retry record in the database, add
/* Precompile some regex that are used to recognize parameters in response
to an EHLO command, if they aren't already compiled. */
- deliver_init();
+ smtp_deliver_init();
/* Now sort the addresses if required, and do the deliveries. The yield of
do_remote_deliveries is FALSE when mua_wrapper is set and all addresses
/* Send DSN for successful messages if requested */
addr_senddsn = NULL;
-for (addr_dsntmp = addr_succeed; addr_dsntmp; addr_dsntmp = addr_dsntmp->next)
+for (address_item * a = addr_succeed; a; a = a->next)
{
/* af_ignore_error not honored here. it's not an error */
DEBUG(D_deliver) debug_printf("DSN: processing router : %s\n"
"DSN: processing successful delivery address: %s\n"
"DSN: Sender_address: %s\n"
- "DSN: orcpt: %s flags: %d\n"
+ "DSN: orcpt: %s flags: 0x%x\n"
"DSN: envid: %s ret: %d\n"
"DSN: Final recipient: %s\n"
"DSN: Remote SMTP server supports DSN: %d\n",
- addr_dsntmp->router ? addr_dsntmp->router->name : US"(unknown)",
- addr_dsntmp->address,
+ a->router ? a->router->name : US"(unknown)",
+ a->address,
sender_address,
- addr_dsntmp->dsn_orcpt ? addr_dsntmp->dsn_orcpt : US"NULL",
- addr_dsntmp->dsn_flags,
+ a->dsn_orcpt ? a->dsn_orcpt : US"NULL",
+ a->dsn_flags,
dsn_envid ? dsn_envid : US"NULL", dsn_ret,
- addr_dsntmp->address,
- addr_dsntmp->dsn_aware
+ a->address,
+ a->dsn_aware
);
/* send report if next hop not DSN aware or a router flagged "last DSN hop"
- and a report was requested */
- if ( ( addr_dsntmp->dsn_aware != dsn_support_yes
- || addr_dsntmp->dsn_flags & rf_dsnlasthop
- )
- && addr_dsntmp->dsn_flags & rf_notify_success
+ and a report was requested */
+
+ if ( (a->dsn_aware != dsn_support_yes || a->dsn_flags & rf_dsnlasthop)
+ && a->dsn_flags & rf_notify_success
)
{
/* copy and relink address_item and send report with all of them at once later */
address_item * addr_next = addr_senddsn;
- addr_senddsn = store_get(sizeof(address_item));
- *addr_senddsn = *addr_dsntmp;
+ addr_senddsn = store_get(sizeof(address_item), FALSE);
+ *addr_senddsn = *a;
addr_senddsn->next = addr_next;
}
else
if (pid < 0) /* Creation of child failed */
{
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Process %d (parent %d) failed to "
- "create child process to send failure message: %s", getpid(),
+ "create child process to send success-dsn message: %s", getpid(),
getppid(), strerror(errno));
DEBUG(D_deliver) debug_printf("DSN: child_open_exim failed\n");
transport_ctx tctx = {{0}};
DEBUG(D_deliver)
- debug_printf("sending error message to: %s\n", sender_address);
+ debug_printf("sending success-dsn to: %s\n", sender_address);
/* build unique id for MIME boundary */
bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
if (errors_reply_to)
fprintf(f, "Reply-To: %s\n", errors_reply_to);
+ moan_write_from(f);
fprintf(f, "Auto-Submitted: auto-generated\n"
- "From: Mail Delivery System <Mailer-Daemon@%s>\n"
"To: %s\n"
- "Subject: Delivery Status Notification\n"
- "Content-Type: multipart/report; report-type=delivery-status; boundary=%s\n"
+ "Subject: Delivery Status Notification\n",
+ sender_address);
+ moan_write_references(f, NULL);
+ fprintf(f, "Content-Type: multipart/report;"
+ " report-type=delivery-status; boundary=%s\n"
"MIME-Version: 1.0\n\n"
"--%s\n"
"This message was created automatically by mail delivery software.\n"
" ----- The following addresses had successful delivery notifications -----\n",
- qualify_domain_sender, sender_address, bound, bound);
+ bound, bound);
- for (addr_dsntmp = addr_senddsn; addr_dsntmp;
- addr_dsntmp = addr_dsntmp->next)
+ for (address_item * a = addr_senddsn; a; a = a->next)
fprintf(f, "<%s> (relayed %s)\n\n",
- addr_dsntmp->address,
- addr_dsntmp->dsn_flags & rf_dsnlasthop ? "via non DSN router"
- : addr_dsntmp->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer"
+ a->address,
+ a->dsn_flags & rf_dsnlasthop ? "via non DSN router"
+ : a->dsn_aware == dsn_support_no ? "to non-DSN-aware mailer"
: "via non \"Remote SMTP\" router"
);
}
fputc('\n', f);
- for (addr_dsntmp = addr_senddsn;
- addr_dsntmp;
- addr_dsntmp = addr_dsntmp->next)
+ for (address_item * a = addr_senddsn; a; a = a->next)
{
- if (addr_dsntmp->dsn_orcpt)
- fprintf(f,"Original-Recipient: %s\n", addr_dsntmp->dsn_orcpt);
+ host_item * hu;
- fprintf(f, "Action: delivered\n"
- "Final-Recipient: rfc822;%s\n"
- "Status: 2.0.0\n",
- addr_dsntmp->address);
+ print_dsn_addr_action(f, a, US"delivered", US"2.0.0");
- if (addr_dsntmp->host_used && addr_dsntmp->host_used->name)
+ if ((hu = a->host_used) && hu->name)
fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; 250 Ok\n\n",
- addr_dsntmp->host_used->name);
+ hu->name);
else
fprintf(f, "Diagnostic-Code: X-Exim; relayed via non %s router\n\n",
- addr_dsntmp->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP");
+ a->dsn_flags & rf_dsnlasthop ? "DSN" : "SMTP");
}
fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound);
mark the recipient done. */
if ( addr_failed->prop.ignore_error
- || addr_failed->dsn_flags & (rf_dsnflags & ~rf_notify_failure)
+ || addr_failed->dsn_flags & rf_dsnflags
+ && !(addr_failed->dsn_flags & rf_notify_failure)
)
{
addr = addr_failed;
#ifndef DISABLE_EVENT
msg_event_raise(US"msg:fail:delivery", addr);
#endif
- log_write(0, LOG_MAIN, "%s%s%s%s: error ignored",
+ log_write(0, LOG_MAIN, "%s%s%s%s: error ignored%s",
addr->address,
!addr->parent ? US"" : US" <",
!addr->parent ? US"" : addr->parent->address,
- !addr->parent ? US"" : US">");
+ !addr->parent ? US"" : US">",
+ addr->prop.ignore_error
+ ? US"" : US": RFC 3461 DSN, failure notify not requested");
address_done(addr, logtod);
child_done(addr, logtod);
fprintf(fp, "Auto-Submitted: auto-replied\n");
moan_write_from(fp);
fprintf(fp, "To: %s\n", bounce_recipient);
+ moan_write_references(fp, NULL);
/* generate boundary string and output MIME-Headers */
bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
for (addr = handled_addr; addr; addr = addr->next)
{
host_item * hu;
- fprintf(fp, "Action: failed\n"
- "Final-Recipient: rfc822;%s\n"
- "Status: 5.0.0\n",
- addr->address);
+
+ print_dsn_addr_action(fp, addr, US"failed", US"5.0.0");
+
if ((hu = addr->host_used) && hu->name)
{
fprintf(fp, "Remote-MTA: dns; %s\n", hu->name);
/* In the test harness, let the child do it's thing first. */
- if (f.running_in_test_harness) millisleep(500);
+ testharness_pause_ms(500);
/* If the process failed, there was some disaster in setting up the
error message. Unless the message is very old, ensure that addr_defer
int show_time;
int queue_time = time(NULL) - received_time.tv_sec;
- /* When running in the test harness, there's an option that allows us to
- fudge this time so as to get repeatability of the tests. Take the first
- time off the list. In queue runs, the list pointer gets updated in the
- calling process. */
-
- if (f.running_in_test_harness && fudged_queue_times[0] != 0)
- {
- int qt = readconf_readtime(fudged_queue_times, '/', FALSE);
- if (qt >= 0)
- {
- DEBUG(D_deliver) debug_printf("fudged queue_times = %s\n",
- fudged_queue_times);
- queue_time = qt;
- }
- }
+ queue_time = test_harness_fudged_queue_time(queue_time);
/* See how many warnings we should have sent by now */
DEBUG(D_deliver)
{
- debug_printf("time on queue = %s id %s addr %s\n", readconf_printtime(queue_time), message_id, addr_defer->address);
+ debug_printf("time on queue = %s id %s addr %s\n",
+ readconf_printtime(queue_time), message_id, addr_defer->address);
debug_printf("warning counts: required %d done %d\n", count,
warning_count);
}
fprintf(f, "Auto-Submitted: auto-replied\n");
moan_write_from(f);
fprintf(f, "To: %s\n", recipients);
+ moan_write_references(f, NULL);
/* generated boundary string and output MIME-Headers */
bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
/* List the addresses, with error information if allowed */
- /* store addr_defer for machine readable part */
- address_item *addr_dsndefer = addr_defer;
fputc('\n', f);
- while (addr_defer)
+ for (address_item * addr = addr_defer; addr; addr = addr->next)
{
- address_item *addr = addr_defer;
- addr_defer = addr->next;
if (print_address_information(addr, f, US" ", US"\n ", US""))
print_address_error(addr, f, US"Delay reason: ");
fputc('\n', f);
}
fputc('\n', f);
- for ( ; addr_dsndefer; addr_dsndefer = addr_dsndefer->next)
+ for (address_item * addr = addr_defer; addr; addr = addr->next)
{
- if (addr_dsndefer->dsn_orcpt)
- fprintf(f, "Original-Recipient: %s\n", addr_dsndefer->dsn_orcpt);
-
- fprintf(f, "Action: delayed\n"
- "Final-Recipient: rfc822;%s\n"
- "Status: 4.0.0\n",
- addr_dsndefer->address);
- if (addr_dsndefer->host_used && addr_dsndefer->host_used->name)
+ host_item * hu;
+
+ print_dsn_addr_action(f, addr, US"delayed", US"4.0.0");
+
+ if ((hu = addr->host_used) && hu->name)
{
- fprintf(f, "Remote-MTA: dns; %s\n",
- addr_dsndefer->host_used->name);
- print_dsn_diagnostic_code(addr_dsndefer, f);
+ fprintf(f, "Remote-MTA: dns; %s\n", hu->name);
+ print_dsn_diagnostic_code(addr, f);
}
fputc('\n', f);
}
(void)close(deliver_datafile);
deliver_datafile = -1;
DEBUG(D_deliver) debug_printf("end delivery of %s\n", id);
+#ifdef MEASURE_TIMING
+report_time_since(×tamp_startup, US"delivery end"); /* testcase 0005 */
+#endif
/* It is unlikely that there will be any cached resources, since they are
released after routing, and in the delivery subprocesses. However, it's
void
-deliver_init(void)
+tcp_init(void)
{
#ifdef EXIM_TFO_PROBE
tfo_probe();
#else
f.tcp_fastopen_ok = TRUE;
#endif
-
-
-if (!regex_PIPELINING) regex_PIPELINING =
- regex_must_compile(US"\\n250[\\s\\-]PIPELINING(\\s|\\n|$)", FALSE, TRUE);
-
-if (!regex_SIZE) regex_SIZE =
- regex_must_compile(US"\\n250[\\s\\-]SIZE(\\s|\\n|$)", FALSE, TRUE);
-
-if (!regex_AUTH) regex_AUTH =
- regex_must_compile(AUTHS_REGEX, FALSE, TRUE);
-
-#ifdef SUPPORT_TLS
-if (!regex_STARTTLS) regex_STARTTLS =
- regex_must_compile(US"\\n250[\\s\\-]STARTTLS(\\s|\\n|$)", FALSE, TRUE);
-#endif
-
-if (!regex_CHUNKING) regex_CHUNKING =
- regex_must_compile(US"\\n250[\\s\\-]CHUNKING(\\s|\\n|$)", FALSE, TRUE);
-
-#ifndef DISABLE_PRDR
-if (!regex_PRDR) regex_PRDR =
- regex_must_compile(US"\\n250[\\s\\-]PRDR(\\s|\\n|$)", FALSE, TRUE);
-#endif
-
-#ifdef SUPPORT_I18N
-if (!regex_UTF8) regex_UTF8 =
- regex_must_compile(US"\\n250[\\s\\-]SMTPUTF8(\\s|\\n|$)", FALSE, TRUE);
-#endif
-
-if (!regex_DSN) regex_DSN =
- regex_must_compile(US"\\n250[\\s\\-]DSN(\\s|\\n|$)", FALSE, TRUE);
-
-if (!regex_IGNOREQUOTA) regex_IGNOREQUOTA =
- regex_must_compile(US"\\n250[\\s\\-]IGNOREQUOTA(\\s|\\n|$)", FALSE, TRUE);
-
-#ifdef EXPERIMENTAL_PIPE_CONNECT
-if (!regex_EARLY_PIPE) regex_EARLY_PIPE =
- regex_must_compile(US"\\n250[\\s\\-]" EARLY_PIPE_FEATURE_NAME "(\\s|\\n|$)", FALSE, TRUE);
-#endif
}
smtp_peer_options = cutthrough.peer_options;
continue_sequence = 0;
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
if (cutthrough.is_tls)
{
int pfd[2], pid;
else if (pid == 0) /* child: fork again to totally disconnect */
{
- if (f.running_in_test_harness) millisleep(100); /* let parent debug out */
+ testharness_pause_ms(100); /* let parent debug out */
/* does not return */
smtp_proxy_tls(cutthrough.cctx.tls_ctx, big_buffer, big_buffer_size,
pfd, 5*60);
}
return; /* compiler quietening; control does not reach here. */
-#ifdef SUPPORT_TLS
+#ifndef DISABLE_TLS
fail:
log_write(0,
LOG_MAIN | (exec_type == CEE_EXEC_EXIT ? LOG_PANIC : LOG_PANIC_DIE),