#include "exim.h"
+#include <assert.h>
/* Data block for keeping track of subprocesses for parallel remote
+/*************************************************
+* Delivery logging support functions *
+*************************************************/
+
+/* The LOGGING() checks in d_log_interface() are complicated for backwards
+compatibility. When outgoing interface logging was originally added, it was
+conditional on just incoming_interface (which is off by default). The
+outgoing_interface option is on by default to preserve this behaviour, but
+you can enable incoming_interface and disable outgoing_interface to get I=
+fields on incoming lines only.
+
+Arguments:
+ s The log line buffer
+ sizep Pointer to the buffer size
+ ptrp Pointer to current index into buffer
+ addr The address to be logged
+
+Returns: New value for s
+*/
static uschar *
-d_hostlog(uschar * s, int * sizep, int * ptrp, address_item * addr)
+d_log_interface(uschar *s, int *sizep, int *ptrp)
{
- s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
- US" [", addr->host_used->address, US"]");
- if ((log_extra_selector & LX_outgoing_port) != 0)
- s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
- addr->host_used->port));
- return s;
+if (LOGGING(incoming_interface) && LOGGING(outgoing_interface)
+ && sending_ip_address != NULL)
+ {
+ s = string_append(s, sizep, ptrp, 2, US" I=[", sending_ip_address);
+ if (LOGGING(outgoing_port))
+ s = string_append(s, sizep, ptrp, 2, US"]:",
+ string_sprintf("%d", sending_port));
+ else
+ s = string_cat(s, sizep, ptrp, "]", 1);
+ }
+return s;
+}
+
+
+
+static uschar *
+d_hostlog(uschar *s, int *sizep, int *ptrp, address_item *addr)
+{
+s = string_append(s, sizep, ptrp, 5, US" H=", addr->host_used->name,
+ US" [", addr->host_used->address, US"]");
+if (LOGGING(outgoing_port))
+ s = string_append(s, sizep, ptrp, 2, US":", string_sprintf("%d",
+ addr->host_used->port));
+return d_log_interface(s, sizep, ptrp);
}
+
+
#ifdef SUPPORT_TLS
static uschar *
d_tlslog(uschar * s, int * sizep, int * ptrp, address_item * addr)
{
- if ((log_extra_selector & LX_tls_cipher) != 0 && addr->cipher != NULL)
- s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
- if ((log_extra_selector & LX_tls_certificate_verified) != 0 &&
- addr->cipher != NULL)
- s = string_append(s, sizep, ptrp, 2, US" CV=",
- testflag(addr, af_cert_verified)
- ?
+if (LOGGING(tls_cipher) && addr->cipher != NULL)
+ s = string_append(s, sizep, ptrp, 2, US" X=", addr->cipher);
+if (LOGGING(tls_certificate_verified) && addr->cipher != NULL)
+ s = string_append(s, sizep, ptrp, 2, US" CV=",
+ testflag(addr, af_cert_verified)
+ ?
#ifdef EXPERIMENTAL_DANE
- testflag(addr, af_dane_verified)
- ? "dane"
- :
+ testflag(addr, af_dane_verified)
+ ? "dane"
+ :
#endif
- "yes"
- : "no");
- if ((log_extra_selector & LX_tls_peerdn) != 0 && addr->peerdn != NULL)
- s = string_append(s, sizep, ptrp, 3, US" DN=\"",
- string_printing(addr->peerdn), US"\"");
- return s;
+ "yes"
+ : "no");
+if (LOGGING(tls_peerdn) && addr->peerdn != NULL)
+ s = string_append(s, sizep, ptrp, 3, US" DN=\"",
+ string_printing(addr->peerdn), US"\"");
+return s;
}
#endif
s = reset_point = store_get(size);
-log_address = string_log_address(addr, (log_write_selector & L_all_parents) != 0, TRUE);
+log_address = string_log_address(addr, LOGGING(all_parents), TRUE);
if (msg)
s = string_append(s, &size, &ptr, 3, host_and_ident(TRUE), US" ", log_address);
else
s = string_append(s, &size, &ptr, 2, US"> ", log_address);
}
-if (log_extra_selector & LX_incoming_interface && sending_ip_address)
- s = string_append(s, &size, &ptr, 3, US" I=[", sending_ip_address, US"]");
- /* for the port: string_sprintf("%d", sending_port) */
-
-if ((log_extra_selector & LX_sender_on_delivery) != 0 || msg)
+if (LOGGING(sender_on_delivery) || msg)
s = string_append(s, &size, &ptr, 3, US" F=<",
#ifdef EXPERIMENTAL_INTERNATIONAL
testflag(addr, af_utf8_downcvt)
when it is not set is for a delivery to /dev/null which is optimised by not
being run at all. */
-if (used_return_path != NULL &&
- (log_extra_selector & LX_return_path_on_delivery) != 0)
+if (used_return_path != NULL && LOGGING(return_path_on_delivery))
s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
if (msg)
s = string_append(s, &size, &ptr, 2, US" T=", addr->transport->name);
-if ((log_extra_selector & LX_delivery_size) != 0)
+if (LOGGING(delivery_size))
s = string_append(s, &size, &ptr, 2, US" S=",
string_sprintf("%d", transport_count));
{
if (addr->host_list)
s = string_append(s, &size, &ptr, 2, US" H=", addr->host_list->name);
+ s = d_log_interface(s, &size, &ptr);
if (addr->shadow_message != NULL)
s = string_cat(s, &size, &ptr, addr->shadow_message,
Ustrlen(addr->shadow_message));
if (addr->auth_id)
{
s = string_append(s, &size, &ptr, 2, US":", addr->auth_id);
- if (log_extra_selector & LX_smtp_mailauth && addr->auth_sndr)
+ if (LOGGING(smtp_mailauth) && addr->auth_sndr)
s = string_append(s, &size, &ptr, 2, US":", addr->auth_sndr);
}
}
/* confirmation message (SMTP (host_used) and LMTP (driver_name)) */
-if (log_extra_selector & LX_smtp_confirmation &&
- addr->message &&
+if (LOGGING(smtp_confirmation) && addr->message &&
(addr->host_used || Ustrcmp(addr->transport->driver_name, "lmtp") == 0))
{
unsigned i;
/* Time on queue and actual time taken to deliver */
-if ((log_extra_selector & LX_queue_time) != 0)
+if (LOGGING(queue_time))
s = string_append(s, &size, &ptr, 2, US" QT=",
readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
-if ((log_extra_selector & LX_deliver_time) != 0)
+if (LOGGING(deliver_time))
s = string_append(s, &size, &ptr, 2, US" DT=",
readconf_printtime(addr->more_errno));
delivery_log(LOG_MAIN, addr, logchar, NULL);
#ifdef SUPPORT_TLS
- if (tls_out.ourcert)
- {
- tls_free_cert(tls_out.ourcert);
- tls_out.ourcert = NULL;
- }
- if (tls_out.peercert)
- {
- tls_free_cert(tls_out.peercert);
- tls_out.peercert = NULL;
- }
+ tls_free_cert(&tls_out.ourcert);
+ tls_free_cert(&tls_out.peercert);
tls_out.cipher = NULL;
tls_out.peerdn = NULL;
tls_out.ocsp = OCSP_NOT_REQ;
/* 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. */
- log_address = string_log_address(addr,
- (log_write_selector & L_all_parents) != 0, result == OK);
+ log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
/* 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. */
- log_address = string_log_address(addr,
- (log_write_selector & L_all_parents) != 0, result == OK);
+ log_address = string_log_address(addr, LOGGING(all_parents), result == OK);
s = string_cat(s, &size, &ptr, log_address, Ustrlen(log_address));
- if ((log_extra_selector & LX_sender_on_delivery) != 0)
+ if (LOGGING(sender_on_delivery))
s = string_append(s, &size, &ptr, 3, US" F=<", sender_address, US">");
/* Return path may not be set if no delivery actually happened */
- if (used_return_path != NULL &&
- (log_extra_selector & LX_return_path_on_delivery) != 0)
+ if (used_return_path != NULL && LOGGING(return_path_on_delivery))
s = string_append(s, &size, &ptr, 3, US" P=<", used_return_path, US">");
if (addr->router != NULL)
break;
}
- addr->transport_return = *ptr++;
- addr->special_action = *ptr++;
- memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
- ptr += sizeof(addr->basic_errno);
- memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
- ptr += sizeof(addr->more_errno);
- memcpy(&(addr->flags), ptr, sizeof(addr->flags));
- ptr += sizeof(addr->flags);
- addr->message = (*ptr)? string_copy(ptr) : NULL;
- while(*ptr++);
- addr->user_message = (*ptr)? string_copy(ptr) : NULL;
- while(*ptr++);
-
- /* Always two strings for host information, followed by the port number and DNSSEC mark */
-
- if (*ptr != 0)
+ switch (subid)
{
- h = store_get(sizeof(host_item));
- h->name = string_copy(ptr);
- while (*ptr++);
- h->address = string_copy(ptr);
- while(*ptr++);
- memcpy(&(h->port), ptr, sizeof(h->port));
- ptr += sizeof(h->port);
- h->dnssec = *ptr == '2' ? DS_YES
- : *ptr == '1' ? DS_NO
- : DS_UNK;
- ptr++;
- addr->host_used = h;
- }
- else ptr++;
+#ifdef EXPERIMENTAL_DSN_INFO
+ case '1': /* must arrive before A0, and applies to that addr */
+ /* Two strings: smtp_greeting and helo_response */
+ addr->smtp_greeting = string_copy(ptr);
+ while(*ptr++);
+ addr->helo_response = string_copy(ptr);
+ while(*ptr++);
+ break;
+#endif
- /* Finished with this address */
+ case '0':
+ addr->transport_return = *ptr++;
+ addr->special_action = *ptr++;
+ memcpy(&(addr->basic_errno), ptr, sizeof(addr->basic_errno));
+ ptr += sizeof(addr->basic_errno);
+ memcpy(&(addr->more_errno), ptr, sizeof(addr->more_errno));
+ ptr += sizeof(addr->more_errno);
+ memcpy(&(addr->flags), ptr, sizeof(addr->flags));
+ ptr += sizeof(addr->flags);
+ addr->message = (*ptr)? string_copy(ptr) : NULL;
+ while(*ptr++);
+ addr->user_message = (*ptr)? string_copy(ptr) : NULL;
+ while(*ptr++);
- addr = addr->next;
+ /* Always two strings for host information, followed by the port number and DNSSEC mark */
+
+ if (*ptr != 0)
+ {
+ h = store_get(sizeof(host_item));
+ h->name = string_copy(ptr);
+ while (*ptr++);
+ h->address = string_copy(ptr);
+ while(*ptr++);
+ memcpy(&(h->port), ptr, sizeof(h->port));
+ ptr += sizeof(h->port);
+ h->dnssec = *ptr == '2' ? DS_YES
+ : *ptr == '1' ? DS_NO
+ : DS_UNK;
+ ptr++;
+ addr->host_used = h;
+ }
+ else ptr++;
+
+ /* Finished with this address */
+
+ addr = addr->next;
+ break;
+ }
break;
/* Local interface address/port */
for (r = addr->retries; r != NULL; r = r->next)
{
- uschar *ptr;
sprintf(CS big_buffer, "%c%.500s", r->flags, r->key);
ptr = big_buffer + Ustrlen(big_buffer+2) + 3;
memcpy(ptr, &(r->basic_errno), sizeof(r->basic_errno));
rmt_dlv_checked_write(fd, 'R', '0', big_buffer, ptr - big_buffer);
}
- /* The rest of the information goes in an 'A' item. */
+#ifdef EXPERIMENTAL_DSN_INFO
+/*um, are they really per-addr? Other per-conn stuff is not (auth, tls). But host_used is! */
+ if (addr->smtp_greeting)
+ {
+ ptr = big_buffer;
+ DEBUG(D_deliver) debug_printf("smtp_greeting '%s'\n", addr->smtp_greeting);
+ sprintf(CS ptr, "%.128s", addr->smtp_greeting);
+ while(*ptr++);
+ if (addr->helo_response)
+ {
+ DEBUG(D_deliver) debug_printf("helo_response '%s'\n", addr->helo_response);
+ sprintf(CS ptr, "%.128s", addr->helo_response);
+ while(*ptr++);
+ }
+ else
+ *ptr++ = '\0';
+ rmt_dlv_checked_write(fd, 'A', '1', big_buffer, ptr - big_buffer);
+ }
+#endif
+
+ /* The rest of the information goes in an 'A0' item. */
- ptr = big_buffer + 2;
sprintf(CS big_buffer, "%c%c", addr->transport_return,
addr->special_action);
+ ptr = big_buffer + 2;
memcpy(ptr, &(addr->basic_errno), sizeof(addr->basic_errno));
ptr += sizeof(addr->basic_errno);
memcpy(ptr, &(addr->more_errno), sizeof(addr->more_errno));
}
/* Local interface address/port */
- if (log_extra_selector & LX_incoming_interface && sending_ip_address)
+#ifdef EXPERIMENTAL_DSN_INFO
+ if (sending_ip_address)
+#else
+ if (LOGGING(incoming_interface) && sending_ip_address)
+#endif
{
uschar * ptr = big_buffer;
sprintf(CS ptr, "%.128s", sending_ip_address);
for (addr = handled_addr; addr; addr = addr->next)
{
+ host_item * hu;
fprintf(f, "Action: failed\n"
"Final-Recipient: rfc822;%s\n"
"Status: 5.0.0\n",
addr->address);
- if (addr->host_used && addr->host_used->name)
- {
- fprintf(f, "Remote-MTA: dns; %s\n",
- addr->host_used->name);
- print_dsn_diagnostic_code(addr, f);
- }
+ if ((hu = addr->host_used) && hu->name)
+ {
+ const uschar * s;
+ fprintf(f, "Remote-MTA: dns; %s\n",
+ hu->name);
+#ifdef EXPERIMENTAL_DSN_INFO
+ if (hu->address)
+ {
+ uschar * p = hu->port == 25
+ ? US"" : string_sprintf(":%d", hu->port);
+ fprintf(f, "Remote-MTA: X-ip; [%s]%s\n", hu->address, p);
+ }
+ if ((s = addr->smtp_greeting) && *s)
+ fprintf(f, "X-Remote-MTA-smtp-greeting: X-str; %s\n", s);
+ if ((s = addr->helo_response) && *s)
+ fprintf(f, "X-Remote-MTA-helo-response: X-str; %s\n", s);
+ if ((s = addr->message) && *s)
+ fprintf(f, "X-Exim-Diagnostic: X-str; %s\n", s);
+#endif
+ print_dsn_diagnostic_code(addr, f);
+ }
fputc('\n', f);
}
/* Log the end of this message, with queue time if requested. */
- if ((log_extra_selector & LX_queue_time_overall) != 0)
+ if (LOGGING(queue_time_overall))
log_write(0, LOG_MAIN, "Completed QT=%s",
readconf_printtime( (int) ((long)time(NULL) - (long)received_time)) );
else
uschar *
deliver_get_sender_address (uschar * id)
{
+int rc;
+uschar * new_sender_address,
+ * save_sender_address;
+
if (!spool_open_datafile(id))
return NULL;
+/* Save and restore the global sender_address. I'm not sure if we should
+not save/restore all the other global variables too, because
+spool_read_header() may change all of them. But OTOH, when this
+deliver_get_sender_address() gets called, the current message is done
+already and nobody needs the globals anymore. (HS12, 2015-08-21) */
+
sprintf(CS spoolname, "%s-H", id);
-if (spool_read_header(spoolname, TRUE, TRUE) != spool_read_OK)
+save_sender_address = sender_address;
+
+rc = spool_read_header(spoolname, TRUE, TRUE);
+
+new_sender_address = sender_address;
+sender_address = save_sender_address;
+
+if (rc != spool_read_OK)
return NULL;
+assert(new_sender_address);
+
(void)close(deliver_datafile);
deliver_datafile = -1;
-return sender_address;
+return new_sender_address;
}
/* vi: aw ai sw=2