-#ifdef EXPERIMENTAL_TPDA
-int
-tpda_raise_event(uschar * action, uschar * event, uschar * ev_data)
+#ifdef EXPERIMENTAL_EVENT
+uschar *
+event_raise(uschar * action, uschar * event, uschar * ev_data)
{
uschar * s;
if (action)
{
DEBUG(D_deliver)
- debug_printf("TPDA(%s): tpda_event_action=|%s| tpda_delivery_IP=%s\n",
+ debug_printf("Event(%s): event_action=|%s| delivery_IP=%s\n",
event,
action, deliver_host_address);
- tpda_event = event;
- tpda_data = ev_data;
+ event_name = event;
+ event_data = ev_data;
if (!(s = expand_string(action)) && *expand_string_message)
log_write(0, LOG_MAIN|LOG_PANIC,
- "failed to expand tpda_event_action %s in %s: %s\n",
+ "failed to expand event_action %s in %s: %s\n",
event, transport_name, expand_string_message);
- tpda_event = tpda_data = NULL;
+ event_name = event_data = NULL;
/* If the expansion returns anything but an empty string, flag for
the caller to modify his normal processing
if (s && *s)
{
DEBUG(D_deliver)
- debug_printf("TPDA(%s): event_action returned \"%s\"\n", event, s);
- return DEFER;
+ debug_printf("Event(%s): event_action returned \"%s\"\n", event, s);
+ return s;
}
}
-return OK;
+return NULL;
}
static void
-tpda_msg_event(uschar * event, address_item * addr)
+msg_event_raise(uschar * event, address_item * addr)
{
uschar * save_domain = deliver_domain;
uschar * save_local = deliver_localpart;
+uschar * save_host = deliver_host;
if (!addr->transport)
return;
transport_name = addr->transport->name;
deliver_domain = addr->domain;
deliver_localpart = addr->local_part;
+deliver_host = addr->host_used ? addr->host_used->name : NULL;
-(void) tpda_raise_event(addr->transport->tpda_event_action, event,
+(void) event_raise(addr->transport->event_action, event,
addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0
? addr->message : NULL);
+deliver_host = save_host;
deliver_localpart = save_local;
deliver_domain = save_domain;
router_name = transport_name = NULL;
}
-#endif /*EXPERIMENTAL_TPDA*/
+#endif /*EXPERIMENTAL_EVENT*/
uschar *s; /* building log lines; */
void *reset_point; /* released afterwards. */
-
/* 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
have a pointer to the host item that succeeded; local deliveries can have a
pointer to a single host item in their host list, for use by the transport. */
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
/* presume no successful remote delivery */
lookup_dnssec_authenticated = NULL;
#endif
if (continue_sequence > 1)
s = string_cat(s, &size, &ptr, US"*", 1);
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
deliver_host_address = addr->host_used->address;
deliver_host_port = addr->host_used->port;
+ deliver_host = addr->host_used->name;
/* DNS lookup status */
lookup_dnssec_authenticated = addr->host_used->dnssec==DS_YES ? US"yes"
s[ptr] = 0;
log_write(0, flags, "%s", s);
-#ifdef EXPERIMENTAL_TPDA
-/*XXX cutthrough calls this also for non-delivery...*/
-tpda_msg_event(US"msg:delivery", addr);
+#ifdef EXPERIMENTAL_EVENT
+if (!msg) msg_event_raise(US"msg:delivery", addr);
#endif
store_reset(reset_point);
uschar *s; /* building log lines; */
void *reset_point; /* released afterwards. */
-
DEBUG(D_deliver) debug_printf("post-process %s (%d)\n", addr->address, result);
/* Set up driver kind and name for logging. Disable logging if the router or
child_done(addr, now);
}
- /* Certificates for logging (via TPDA) */
+ /* Certificates for logging (via events) */
#ifdef SUPPORT_TLS
tls_out.ourcert = addr->ourcert;
addr->ourcert = NULL;
s = string_append(s, &size, &ptr, 2, US": ",
US strerror(addr->basic_errno));
+ if (addr->host_used)
+ s = string_append(s, &size, &ptr, 5,
+ US" H=", addr->host_used->name,
+ US" [", addr->host_used->address, US"]");
+
if (addr->message != NULL)
s = string_append(s, &size, &ptr, 2, US": ", addr->message);
log_write(0, LOG_MAIN, "** %s", s);
-#ifdef EXPERIMENTAL_TPDA
- tpda_msg_event(US"msg:fail:delivery", addr);
+#ifdef EXPERIMENTAL_EVENT
+ msg_event_raise(US"msg:fail:delivery", addr);
#endif
store_reset(reset_point);
/* two write() calls would increase the complexity of reading from pipe */
/* convert size to human readable string prepended by id and subid */
-header_length = snprintf(writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
+header_length = snprintf(CS writebuffer, PIPE_HEADER_SIZE+1, "%c%c%05d", id, subid, size);
if (header_length != PIPE_HEADER_SIZE)
{
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "header snprintf failed\n");
#ifndef DISABLE_PRDR
if (addr->flags & af_prdr_used)
rmt_dlv_checked_write(fd, 'P', '0', NULL, 0);
- #endif
+#endif
- #ifdef EXPERIMENTAL_DSN
+#ifdef EXPERIMENTAL_DSN
memcpy(big_buffer, &addr->dsn_aware, sizeof(addr->dsn_aware));
rmt_dlv_checked_write(fd, 'D', '0', big_buffer, sizeof(addr->dsn_aware));
DEBUG(D_deliver) debug_printf("DSN write: addr->dsn_aware = %d\n", addr->dsn_aware);
string_printing(original));
}
+if (addr->host_used)
+ fprintf(f, "\n host %s [%s]",
+ addr->host_used->name, addr->host_used->address);
+
fprintf(f, "%s", CS se);
return yield;
}
}
+#ifdef EXPERIMENTAL_DSN
+/***********************************************************
+* Print Diagnostic-Code for an address *
+************************************************************/
+
+/* This function is called to print the error information out of an address for
+a bounce or a warning message. It tries to format the message reasonably as
+required by RFC 3461 by adding a space after each newline
+we assume that this function is only called if addr->host_used is set and if so
+a useable addr->message is available containing some Exim description with ": \n"
+ending, followed by the L/SMTP error message.
+Arguments:
+ addr the address
+ f the FILE to print on
+
+Returns: nothing
+*/
+
+static void
+print_dsn_diagnostic_code(const address_item *addr, FILE *f)
+{
+uschar * s;
+
+/* check host_used, af_pass_message flag and addr->message for safety reasons */
+if (!addr->host_used && testflag(addr, af_pass_message) && addr->message)
+ return;
+
+/* search first ": ". we assume to find the remote-MTA answer there */
+DEBUG(D_deliver)
+ debug_printf("DSN Diagnostic-Code: addr->dsn_message = %s\n", addr->message);
+if (!(s = Ustrstr(addr->message, ": ")))
+ return; /* not found, bail out */
+
+fprintf(f, "Diagnostic-Code: smtp; ");
+
+s += 2; /* skip ": " */
+while (*s)
+ if (*s == '\\' && s[1] == 'n')
+ {
+ fputs("\n ", f); /* as defined in RFC 3461 */
+ s += 2;
+ }
+ else
+ fputc(*s++, f);
+
+fputc('\n', f);
+}
+#endif /* EXPERIMENTAL_DSN */
/*************************************************
break;
}
-#ifdef EXPERIMENTAL_TPDA
+#ifdef EXPERIMENTAL_EVENT
if (process_recipients != RECIP_ACCEPT)
{
uschar * save_local = deliver_localpart;
deliver_domain = expand_string(
string_sprintf("${domain:%s}", new->address));
- (void) tpda_raise_event(delivery_event_action,
+ (void) event_raise(event_action,
US"msg:fail:internal", new->message);
deliver_localpart = save_local;
{
uschar *s = (addr_failed->user_message != NULL)?
addr_failed->user_message : addr_failed->message;
+ host_item * host;
fprintf(stderr, "Delivery failed: ");
if (addr_failed->basic_errno > 0)
fprintf(stderr, "%s", strerror(addr_failed->basic_errno));
if (s != NULL) fprintf(stderr, ": ");
}
+ if ((host = addr_failed->host_used))
+ fprintf(stderr, "H=%s [%s]: ", host->name, host->address);
if (s == NULL)
{
if (addr_failed->basic_errno <= 0) fprintf(stderr, "unknown error");
FILE *f = fdopen(fd, "wb");
/* header only as required by RFC. only failure DSN needs to honor RET=FULL */
int topt = topt_add_return_path | topt_no_body;
- uschar boundaryStr[64];
+ uschar * bound;
DEBUG(D_deliver) debug_printf("sending error message to: %s\n", sender_address);
/* build unique id for MIME boundary */
- snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d",
- time(NULL), rand());
- DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", boundaryStr);
+ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
+ DEBUG(D_deliver) debug_printf("DSN: MIME boundary: %s\n", bound);
if (errors_reply_to)
fprintf(f, "Reply-To: %s\n", errors_reply_to);
"This message was created automatically by mail delivery software.\n"
" ----- The following addresses had successful delivery notifications -----\n",
- qualify_domain_sender, sender_address, boundaryStr, boundaryStr);
+ qualify_domain_sender, sender_address, bound, bound);
addr_dsntmp = addr_senddsn;
while(addr_dsntmp)
fprintf(f, "--%s\n"
"Content-type: message/delivery-status\n\n"
"Reporting-MTA: dns; %s\n",
- boundaryStr, smtp_active_hostname);
+ bound, smtp_active_hostname);
if (dsn_envid != NULL) {
/* must be decoded from xtext: see RFC 3461:6.3a */
fputc('\n', f);
}
- fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", boundaryStr);
+ fprintf(f, "--%s\nContent-type: text/rfc822-headers\n\n", bound);
fflush(f);
transport_filter_argv = NULL; /* Just in case */
transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0);
fflush(f);
- fprintf(f,"\n");
- fprintf(f,"--%s--\n", boundaryStr);
+ fprintf(f,"\n--%s--\n", bound);
fflush(f);
fclose(f);
int max = (bounce_return_size_limit/DELIVER_IN_BUFFER_SIZE + 1) *
DELIVER_IN_BUFFER_SIZE;
#ifdef EXPERIMENTAL_DSN
- uschar boundaryStr[64];
+ uschar * bound;
uschar *dsnlimitmsg;
uschar *dsnnotifyhdr;
int topt;
#ifdef EXPERIMENTAL_DSN
/* generate boundary string and output MIME-Headers */
- snprintf(boundaryStr, sizeof(boundaryStr)-1, TIME_T_FMT "-eximdsn-%d",
- time(NULL), rand());
+ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
fprintf(f, "Content-Type: multipart/report;"
" report-type=delivery-status; boundary=%s\n"
"MIME-Version: 1.0\n",
- boundaryStr);
+ bound);
#endif
/* Open a template file if one is provided. Log failure to open, but
/* output human readable part as text/plain section */
fprintf(f, "--%s\n"
"Content-type: text/plain; charset=us-ascii\n\n",
- boundaryStr);
+ bound);
#endif
if ((emf_text = next_emf(emf, US"intro")))
fprintf(f, "--%s\n"
"Content-type: message/delivery-status\n\n"
"Reporting-MTA: dns; %s\n",
- boundaryStr, smtp_active_hostname);
+ bound, smtp_active_hostname);
if (dsn_envid)
{
"Status: 5.0.0\n",
addr->address);
if (addr->host_used && addr->host_used->name)
- fprintf(f, "Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n",
- addr->host_used->name, addr->basic_errno);
+ {
+ fprintf(f, "Remote-MTA: dns; %s\n",
+ addr->host_used->name);
+ print_dsn_diagnostic_code(addr, f);
+ }
}
#endif
bounce_return_size_limit is always honored.
*/
- fprintf(f, "\n--%s\n", boundaryStr);
+ fprintf(f, "\n--%s\n", bound);
dsnlimitmsg = US"X-Exim-DSN-Information: Due to administrative limits only headers are returned";
dsnnotifyhdr = NULL;
if (emf)
(void)fclose(emf);
- fprintf(f, "\n--%s--\n", boundaryStr);
+ fprintf(f, "\n--%s--\n", bound);
#endif /*EXPERIMENTAL_DSN*/
/* Close the file, which should send an EOF to the child process
/* Unset deliver_freeze so that we won't try to move the spool files further down */
deliver_freeze = FALSE;
-#ifdef EXPERIMENTAL_TPDA
- (void) tpda_raise_event(delivery_event_action, US"msg:complete", NULL);
+#ifdef EXPERIMENTAL_EVENT
+ (void) event_raise(event_action, US"msg:complete", NULL);
#endif
}
FILE *wmf = NULL;
FILE *f = fdopen(fd, "wb");
#ifdef EXPERIMENTAL_DSN
- uschar boundaryStr[64];
+ uschar * bound;
#endif
if (warn_message_file)
#ifdef EXPERIMENTAL_DSN
/* generated boundary string and output MIME-Headers */
- snprintf(boundaryStr, sizeof(boundaryStr)-1,
- TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
+ bound = string_sprintf(TIME_T_FMT "-eximdsn-%d", time(NULL), rand());
fprintf(f, "Content-Type: multipart/report;"
" report-type=delivery-status; boundary=%s\n"
"MIME-Version: 1.0\n",
- boundaryStr);
+ bound);
#endif
if ((wmf_text = next_emf(wmf, US"header")))
/* output human readable part as text/plain section */
fprintf(f, "--%s\n"
"Content-type: text/plain; charset=us-ascii\n\n",
- boundaryStr);
+ bound);
#endif
if ((wmf_text = next_emf(wmf, US"intro")))
fprintf(f, "\n--%s\n"
"Content-type: message/delivery-status\n\n"
"Reporting-MTA: dns; %s\n",
- boundaryStr,
+ bound,
smtp_active_hostname);
fprintf(f,"Final-Recipient: rfc822;%s\n", addr_dsndefer->address);
fprintf(f,"Status: 4.0.0\n");
if (addr_dsndefer->host_used && addr_dsndefer->host_used->name)
- fprintf(f,"Remote-MTA: dns; %s\nDiagnostic-Code: smtp; %d\n",
- addr_dsndefer->host_used->name, addr_dsndefer->basic_errno);
+ {
+ fprintf(f,"Remote-MTA: dns; %s\n",
+ addr_dsndefer->host_used->name);
+ print_dsn_diagnostic_code(addr_dsndefer, f);
+ }
addr_dsndefer = addr_dsndefer->next;
}
fprintf(f, "\n--%s\n"
"Content-type: text/rfc822-headers\n\n",
- boundaryStr);
+ bound);
fflush(f);
/* header only as required by RFC. only failure DSN needs to honor RET=FULL */
transport_write_message(NULL, fileno(f), topt, 0, NULL, NULL, NULL, NULL, NULL, 0);
fflush(f);
- fprintf(f,"\n--%s--\n", boundaryStr);
+ fprintf(f,"\n--%s--\n", bound);
fflush(f);
#endif /*EXPERIMENTAL_DSN*/