"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/transport.c" between
exim-4.91.tar.xz and exim-4.92.tar.xz

About: Exim is a message transfer agent (MTA).

transport.c  (exim-4.91.tar.xz):transport.c  (exim-4.92.tar.xz)
skipping to change at line 240 skipping to change at line 240
/* This code makes use of alarm() in order to implement the timeout. This /* This code makes use of alarm() in order to implement the timeout. This
isn't a very tidy way of doing things. Using non-blocking I/O with select() isn't a very tidy way of doing things. Using non-blocking I/O with select()
provides a neater approach. However, I don't know how to do this when TLS is provides a neater approach. However, I don't know how to do this when TLS is
in use. */ in use. */
if (transport_write_timeout <= 0) /* No timeout wanted */ if (transport_write_timeout <= 0) /* No timeout wanted */
{ {
rc = rc =
#ifdef SUPPORT_TLS #ifdef SUPPORT_TLS
tls_out.active == fd ? tls_write(FALSE, block, len, more) : tls_out.active.sock == fd ? tls_write(tls_out.active.tls_ctx, block, len, more) :
#endif #endif
#ifdef MSG_MORE #ifdef MSG_MORE
more && !(tctx->options & topt_not_socket) more && !(tctx->options & topt_not_socket)
? send(fd, block, len, MSG_MORE) : ? send(fd, block, len, MSG_MORE) :
#endif #endif
write(fd, block, len); write(fd, block, len);
save_errno = errno; save_errno = errno;
} }
/* Timeout wanted. */ /* Timeout wanted. */
else else
{ {
alarm(local_timeout); ALARM(local_timeout);
rc = rc =
#ifdef SUPPORT_TLS #ifdef SUPPORT_TLS
tls_out.active == fd ? tls_write(FALSE, block, len, more) : tls_out.active.sock == fd ? tls_write(tls_out.active.tls_ctx, block, len, more) :
#endif #endif
#ifdef MSG_MORE #ifdef MSG_MORE
more && !(tctx->options & topt_not_socket) more && !(tctx->options & topt_not_socket)
? send(fd, block, len, MSG_MORE) : ? send(fd, block, len, MSG_MORE) :
#endif #endif
write(fd, block, len); write(fd, block, len);
save_errno = errno; save_errno = errno;
local_timeout = alarm(0); local_timeout = ALARM_CLR(0);
if (sigalrm_seen) if (sigalrm_seen)
{ {
errno = ETIMEDOUT; errno = ETIMEDOUT;
return FALSE; return FALSE;
} }
} }
/* Hopefully, the most common case is success, so test that first. */ /* Hopefully, the most common case is success, so test that first. */
if (rc == len) { transport_count += len; return TRUE; } if (rc == len) { transport_count += len; return TRUE; }
skipping to change at line 369 skipping to change at line 369
format string format format string format
... arguments for format ... arguments for format
Returns: the yield of transport_write_block() Returns: the yield of transport_write_block()
*/ */
BOOL BOOL
transport_write_string(int fd, const char *format, ...) transport_write_string(int fd, const char *format, ...)
{ {
transport_ctx tctx = {{0}}; transport_ctx tctx = {{0}};
gstring gs = { .size = big_buffer_size, .ptr = 0, .s = big_buffer };
va_list ap; va_list ap;
va_start(ap, format); va_start(ap, format);
if (!string_vformat(big_buffer, big_buffer_size, format, ap)) if (!string_vformat(&gs, FALSE, format, ap))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong formatted string in transport") ; log_write(0, LOG_MAIN|LOG_PANIC_DIE, "overlong formatted string in transport") ;
va_end(ap); va_end(ap);
tctx.u.fd = fd; tctx.u.fd = fd;
return transport_write_block(&tctx, big_buffer, Ustrlen(big_buffer), FALSE); return transport_write_block(&tctx, gs.s, gs.ptr, FALSE);
} }
void void
transport_write_reset(int options) transport_write_reset(int options)
{ {
if (!(options & topt_continuation)) chunk_ptr = deliver_out_buffer; if (!(options & topt_continuation)) chunk_ptr = deliver_out_buffer;
nl_partial_match = -1; nl_partial_match = -1;
nl_check_length = nl_escape_length = 0; nl_check_length = nl_escape_length = 0;
} }
skipping to change at line 484 skipping to change at line 486
else else
if (!transport_write_block(tctx, deliver_out_buffer, len, FALSE)) if (!transport_write_block(tctx, deliver_out_buffer, len, FALSE))
return FALSE; return FALSE;
chunk_ptr = deliver_out_buffer; chunk_ptr = deliver_out_buffer;
} }
/* Remove CR before NL if required */ /* Remove CR before NL if required */
if ( *ptr == '\r' && ptr[1] == '\n' if ( *ptr == '\r' && ptr[1] == '\n'
&& !(tctx->options & topt_use_crlf) && !(tctx->options & topt_use_crlf)
&& spool_file_wireformat && f.spool_file_wireformat
) )
ptr++; ptr++;
if ((ch = *ptr) == '\n') if ((ch = *ptr) == '\n')
{ {
int left = end - ptr - 1; /* count of chars left after NL */ int left = end - ptr - 1; /* count of chars left after NL */
/* Insert CR before NL if required */ /* Insert CR before NL if required */
if (tctx->options & topt_use_crlf && !spool_file_wireformat) if (tctx->options & topt_use_crlf && !f.spool_file_wireformat)
*chunk_ptr++ = '\r'; *chunk_ptr++ = '\r';
*chunk_ptr++ = '\n'; *chunk_ptr++ = '\n';
transport_newlines++; transport_newlines++;
/* The check_string test (formerly "from hack") replaces the specific /* The check_string test (formerly "from hack") replaces the specific
string at the start of a line with an escape string (e.g. "From " becomes string at the start of a line with an escape string (e.g. "From " becomes
">From " or "." becomes "..". It is a case-sensitive test. The length ">From " or "." becomes "..". It is a case-sensitive test. The length
check above ensures there is always enough room to insert this string. */ check above ensures there is always enough room to insert this string. */
if (nl_check_length > 0) if (nl_check_length > 0)
skipping to change at line 705 skipping to change at line 707
{ {
if (list) if (list)
{ {
int sep = ':'; /* This is specified as a colon-separated list */ int sep = ':'; /* This is specified as a colon-separated list */
uschar *s, *ss; uschar *s, *ss;
while ((s = string_nextinlist(&list, &sep, NULL, 0))) while ((s = string_nextinlist(&list, &sep, NULL, 0)))
{ {
int len; int len;
if (i == 0) if (i == 0)
if (!(s = expand_string(s)) && !expand_string_forcedfail) if (!(s = expand_string(s)) && !f.expand_string_forcedfail)
{ {
errno = ERRNO_CHHEADER_FAIL; errno = ERRNO_CHHEADER_FAIL;
return FALSE; return FALSE;
} }
len = s ? Ustrlen(s) : 0; len = s ? Ustrlen(s) : 0;
if (strncmpic(h->text, s, len) != 0) continue; if (strncmpic(h->text, s, len) != 0) continue;
ss = h->text + len; ss = h->text + len;
while (*ss == ' ' || *ss == '\t') ss++; while (*ss == ' ' || *ss == '\t') ss++;
if (*ss == ':') break; if (*ss == ':') break;
} }
skipping to change at line 811 skipping to change at line 813
if (s[len-1] != '\n' && !sendfn(tctx, US"\n", 1)) if (s[len-1] != '\n' && !sendfn(tctx, US"\n", 1))
return FALSE; return FALSE;
DEBUG(D_transport) DEBUG(D_transport)
{ {
debug_printf("added header line:\n%s", s); debug_printf("added header line:\n%s", s);
if (s[len-1] != '\n') debug_printf("\n"); if (s[len-1] != '\n') debug_printf("\n");
debug_printf("---\n"); debug_printf("---\n");
} }
} }
} }
else if (!expand_string_forcedfail) else if (!f.expand_string_forcedfail)
{ errno = ERRNO_CHHEADER_FAIL; return FALSE; } { errno = ERRNO_CHHEADER_FAIL; return FALSE; }
} }
/* Separate headers from body with a blank line */ /* Separate headers from body with a blank line */
return sendfn(tctx, US"\n", 1); return sendfn(tctx, US"\n", 1);
} }
/************************************************* /*************************************************
* Write the message * * Write the message *
skipping to change at line 915 skipping to change at line 917
if (!(tctx->options & topt_escape_headers)) if (!(tctx->options & topt_escape_headers))
nl_check_length = -nl_check_length; nl_check_length = -nl_check_length;
/* Write the headers if required, including any that have to be added. If there /* Write the headers if required, including any that have to be added. If there
are header rewriting rules, apply them. The datasource is not the -D spoolfile are header rewriting rules, apply them. The datasource is not the -D spoolfile
so temporarily hide the global that adjusts for its format. */ so temporarily hide the global that adjusts for its format. */
if (!(tctx->options & topt_no_headers)) if (!(tctx->options & topt_no_headers))
{ {
BOOL save_wireformat = spool_file_wireformat; BOOL save_wireformat = f.spool_file_wireformat;
spool_file_wireformat = FALSE; f.spool_file_wireformat = FALSE;
/* Add return-path: if requested. */ /* Add return-path: if requested. */
if (tctx->options & topt_add_return_path) if (tctx->options & topt_add_return_path)
{ {
uschar buffer[ADDRESS_MAXLENGTH + 20]; uschar buffer[ADDRESS_MAXLENGTH + 20];
int n = sprintf(CS buffer, "Return-path: <%.*s>\n", ADDRESS_MAXLENGTH, int n = sprintf(CS buffer, "Return-path: <%.*s>\n", ADDRESS_MAXLENGTH,
return_path); return_path);
if (!write_chunk(tctx, buffer, n)) goto bad; if (!write_chunk(tctx, buffer, n)) goto bad;
} }
skipping to change at line 973 skipping to change at line 975
/* Then the message's headers. Don't write any that are flagged as "old"; /* Then the message's headers. Don't write any that are flagged as "old";
that means they were rewritten, or are a record of envelope rewriting, or that means they were rewritten, or are a record of envelope rewriting, or
were removed (e.g. Bcc). If remove_headers is not null, skip any headers that were removed (e.g. Bcc). If remove_headers is not null, skip any headers that
match any entries therein. Then check addr->prop.remove_headers too, provided that match any entries therein. Then check addr->prop.remove_headers too, provided that
addr is not NULL. */ addr is not NULL. */
if (!transport_headers_send(tctx, &write_chunk)) if (!transport_headers_send(tctx, &write_chunk))
{ {
bad: bad:
spool_file_wireformat = save_wireformat; f.spool_file_wireformat = save_wireformat;
return FALSE; return FALSE;
} }
spool_file_wireformat = save_wireformat; f.spool_file_wireformat = save_wireformat;
} }
/* When doing RFC3030 CHUNKING output, work out how much data would be in a /* When doing RFC3030 CHUNKING output, work out how much data would be in a
last-BDAT, consisting of the current write_chunk() output buffer fill last-BDAT, consisting of the current write_chunk() output buffer fill
(optimally, all of the headers - but it does not matter if we already had to (optimally, all of the headers - but it does not matter if we already had to
flush that buffer with non-last BDAT prependix) plus the amount of body data flush that buffer with non-last BDAT prependix) plus the amount of body data
(as expanded for CRLF lines). Then create and write BDAT(s), and ensure (as expanded for CRLF lines). Then create and write BDAT(s), and ensure
that further use of write_chunk() will not prepend BDATs. that further use of write_chunk() will not prepend BDATs.
The first BDAT written will also first flush any outstanding MAIL and RCPT The first BDAT written will also first flush any outstanding MAIL and RCPT
commands which were buffered thans to PIPELINING. commands which were buffered thans to PIPELINING.
skipping to change at line 1006 skipping to change at line 1008
if ((hsize = chunk_ptr - deliver_out_buffer) < 0) if ((hsize = chunk_ptr - deliver_out_buffer) < 0)
hsize = 0; hsize = 0;
if (!(tctx->options & topt_no_body)) if (!(tctx->options & topt_no_body))
{ {
if ((fsize = lseek(deliver_datafile, 0, SEEK_END)) < 0) return FALSE; if ((fsize = lseek(deliver_datafile, 0, SEEK_END)) < 0) return FALSE;
fsize -= SPOOL_DATA_START_OFFSET; fsize -= SPOOL_DATA_START_OFFSET;
if (size_limit > 0 && fsize > size_limit) if (size_limit > 0 && fsize > size_limit)
fsize = size_limit; fsize = size_limit;
size = hsize + fsize; size = hsize + fsize;
if (tctx->options & topt_use_crlf && !spool_file_wireformat) if (tctx->options & topt_use_crlf && !f.spool_file_wireformat)
size += body_linecount; /* account for CRLF-expansion */ size += body_linecount; /* account for CRLF-expansion */
/* With topt_use_bdat we never do dot-stuffing; no need to /* With topt_use_bdat we never do dot-stuffing; no need to
account for any expansion due to that. */ account for any expansion due to that. */
} }
/* If the message is large, emit first a non-LAST chunk with just the /* If the message is large, emit first a non-LAST chunk with just the
headers, and reap the command responses. This lets us error out early headers, and reap the command responses. This lets us error out early
on RCPT rejects rather than sending megabytes of data. Include headers on RCPT rejects rather than sending megabytes of data. Include headers
on the assumption they are cheap enough and some clever implementations on the assumption they are cheap enough and some clever implementations
skipping to change at line 1053 skipping to change at line 1055
is positioned at the start of its file (following the message id), then write is positioned at the start of its file (following the message id), then write
it, applying the size limit if required. */ it, applying the size limit if required. */
/* If we have a wireformat -D file (CRNL lines, non-dotstuffed, no ending dot) /* If we have a wireformat -D file (CRNL lines, non-dotstuffed, no ending dot)
and we want to send a body without dotstuffing or ending-dot, in-clear, and we want to send a body without dotstuffing or ending-dot, in-clear,
then we can just dump it using sendfile. then we can just dump it using sendfile.
This should get used for CHUNKING output and also for writing the -K file for This should get used for CHUNKING output and also for writing the -K file for
dkim signing, when we had CHUNKING input. */ dkim signing, when we had CHUNKING input. */
#ifdef OS_SENDFILE #ifdef OS_SENDFILE
if ( spool_file_wireformat if ( f.spool_file_wireformat
&& !(tctx->options & (topt_no_body | topt_end_dot)) && !(tctx->options & (topt_no_body | topt_end_dot))
&& !nl_check_length && !nl_check_length
&& tls_out.active != tctx->u.fd && tls_out.active.sock != tctx->u.fd
) )
{ {
ssize_t copied = 0; ssize_t copied = 0;
off_t offset = SPOOL_DATA_START_OFFSET; off_t offset = SPOOL_DATA_START_OFFSET;
/* Write out any header data in the buffer */ /* Write out any header data in the buffer */
if ((len = chunk_ptr - deliver_out_buffer) > 0) if ((len = chunk_ptr - deliver_out_buffer) > 0)
{ {
if (!transport_write_block(tctx, deliver_out_buffer, len, TRUE)) if (!transport_write_block(tctx, deliver_out_buffer, len, TRUE))
skipping to change at line 1087 skipping to change at line 1089
} }
return copied >= 0; return copied >= 0;
} }
#else #else
DEBUG(D_transport) debug_printf("cannot use sendfile for body: no support\n"); DEBUG(D_transport) debug_printf("cannot use sendfile for body: no support\n");
#endif #endif
DEBUG(D_transport) DEBUG(D_transport)
if (!(tctx->options & topt_no_body)) if (!(tctx->options & topt_no_body))
debug_printf("cannot use sendfile for body: %s\n", debug_printf("cannot use sendfile for body: %s\n",
!spool_file_wireformat ? "spoolfile not wireformat" !f.spool_file_wireformat ? "spoolfile not wireformat"
: tctx->options & topt_end_dot ? "terminating dot wanted" : tctx->options & topt_end_dot ? "terminating dot wanted"
: nl_check_length ? "dot- or From-stuffing wanted" : nl_check_length ? "dot- or From-stuffing wanted"
: "TLS output wanted"); : "TLS output wanted");
if (!(tctx->options & topt_no_body)) if (!(tctx->options & topt_no_body))
{ {
int size = size_limit; int size = size_limit;
nl_check_length = abs(nl_check_length); nl_check_length = abs(nl_check_length);
nl_partial_match = 0; nl_partial_match = 0;
skipping to change at line 1116 skipping to change at line 1118
} }
/* A read error on the body will have left len == -1 and errno set. */ /* A read error on the body will have left len == -1 and errno set. */
if (len != 0) return FALSE; if (len != 0) return FALSE;
} }
/* Finished with the check string, and spool-format consideration */ /* Finished with the check string, and spool-format consideration */
nl_check_length = nl_escape_length = 0; nl_check_length = nl_escape_length = 0;
spool_file_wireformat = FALSE; f.spool_file_wireformat = FALSE;
/* If requested, add a terminating "." line (SMTP output). */ /* If requested, add a terminating "." line (SMTP output). */
if (tctx->options & topt_end_dot && !write_chunk(tctx, US".\n", 2)) if (tctx->options & topt_end_dot && !write_chunk(tctx, US".\n", 2))
return FALSE; return FALSE;
/* Write out any remaining data in the buffer before returning. */ /* Write out any remaining data in the buffer before returning. */
return (len = chunk_ptr - deliver_out_buffer) <= 0 || return (len = chunk_ptr - deliver_out_buffer) <= 0 ||
transport_write_block(tctx, deliver_out_buffer, len, FALSE); transport_write_block(tctx, deliver_out_buffer, len, FALSE);
skipping to change at line 1150 skipping to change at line 1152
Arguments: as for internal_transport_write_message() above Arguments: as for internal_transport_write_message() above
Returns: TRUE on success; FALSE (with errno) for any failure Returns: TRUE on success; FALSE (with errno) for any failure
transport_count is incremented by the number of bytes written transport_count is incremented by the number of bytes written
*/ */
BOOL BOOL
transport_write_message(transport_ctx * tctx, int size_limit) transport_write_message(transport_ctx * tctx, int size_limit)
{ {
BOOL last_filter_was_NL = TRUE; BOOL last_filter_was_NL = TRUE;
BOOL save_spool_file_wireformat = spool_file_wireformat; BOOL save_spool_file_wireformat = f.spool_file_wireformat;
int rc, len, yield, fd_read, fd_write, save_errno; int rc, len, yield, fd_read, fd_write, save_errno;
int pfd[2] = {-1, -1}; int pfd[2] = {-1, -1};
pid_t filter_pid, write_pid; pid_t filter_pid, write_pid;
transport_filter_timed_out = FALSE; f.transport_filter_timed_out = FALSE;
/* If there is no filter command set up, call the internal function that does /* If there is no filter command set up, call the internal function that does
the actual work, passing it the incoming fd, and return its result. */ the actual work, passing it the incoming fd, and return its result. */
if ( !transport_filter_argv if ( !transport_filter_argv
|| !*transport_filter_argv || !*transport_filter_argv
|| !**transport_filter_argv || !**transport_filter_argv
) )
return internal_transport_write_message(tctx, size_limit); return internal_transport_write_message(tctx, size_limit);
skipping to change at line 1255 skipping to change at line 1257
/* Writing process creation failed */ /* Writing process creation failed */
if (write_pid < 0) if (write_pid < 0)
{ {
errno = save_errno; /* restore */ errno = save_errno; /* restore */
goto TIDY_UP; goto TIDY_UP;
} }
/* When testing, let the subprocess get going */ /* When testing, let the subprocess get going */
if (running_in_test_harness) millisleep(250); if (f.running_in_test_harness) millisleep(250);
DEBUG(D_transport) DEBUG(D_transport)
debug_printf("process %d writing to transport filter\n", (int)write_pid); debug_printf("process %d writing to transport filter\n", (int)write_pid);
/* Copy the message from the filter to the output fd. A read error leaves len /* Copy the message from the filter to the output fd. A read error leaves len
== -1 and errno set. We need to apply a timeout to the read, to cope with == -1 and errno set. We need to apply a timeout to the read, to cope with
the case when the filter gets stuck, but it can be quite a long one. The the case when the filter gets stuck, but it can be quite a long one. The
default is 5m, but this is now configurable. */ default is 5m, but this is now configurable. */
DEBUG(D_transport) debug_printf("copying from the filter\n"); DEBUG(D_transport) debug_printf("copying from the filter\n");
/* Copy the output of the filter, remembering if the last character was NL. If /* Copy the output of the filter, remembering if the last character was NL. If
no data is returned, that counts as "ended with NL" (default setting of the no data is returned, that counts as "ended with NL" (default setting of the
variable is TRUE). The output should always be unix-format as we converted variable is TRUE). The output should always be unix-format as we converted
any wireformat source on writing input to the filter. */ any wireformat source on writing input to the filter. */
spool_file_wireformat = FALSE; f.spool_file_wireformat = FALSE;
chunk_ptr = deliver_out_buffer; chunk_ptr = deliver_out_buffer;
for (;;) for (;;)
{ {
sigalrm_seen = FALSE; sigalrm_seen = FALSE;
alarm(transport_filter_timeout); ALARM(transport_filter_timeout);
len = read(fd_read, deliver_in_buffer, DELIVER_IN_BUFFER_SIZE); len = read(fd_read, deliver_in_buffer, DELIVER_IN_BUFFER_SIZE);
alarm(0); ALARM_CLR(0);
if (sigalrm_seen) if (sigalrm_seen)
{ {
errno = ETIMEDOUT; errno = ETIMEDOUT;
transport_filter_timed_out = TRUE; f.transport_filter_timed_out = TRUE;
goto TIDY_UP; goto TIDY_UP;
} }
/* If the read was successful, write the block down the original fd, /* If the read was successful, write the block down the original fd,
remembering whether it ends in \n or not. */ remembering whether it ends in \n or not. */
if (len > 0) if (len > 0)
{ {
if (!write_chunk(tctx, deliver_in_buffer, len)) goto TIDY_UP; if (!write_chunk(tctx, deliver_in_buffer, len)) goto TIDY_UP;
last_filter_was_NL = (deliver_in_buffer[len-1] == '\n'); last_filter_was_NL = (deliver_in_buffer[len-1] == '\n');
skipping to change at line 1312 skipping to change at line 1314
break; break;
} }
} }
/* Tidying up code. If yield = FALSE there has been an error and errno is set /* Tidying up code. If yield = FALSE there has been an error and errno is set
to something. Ensure the pipes are all closed and the processes are removed. If to something. Ensure the pipes are all closed and the processes are removed. If
there has been an error, kill the processes before waiting for them, just to be there has been an error, kill the processes before waiting for them, just to be
sure. Also apply a paranoia timeout. */ sure. Also apply a paranoia timeout. */
TIDY_UP: TIDY_UP:
spool_file_wireformat = save_spool_file_wireformat; f.spool_file_wireformat = save_spool_file_wireformat;
save_errno = errno; save_errno = errno;
(void)close(fd_read); (void)close(fd_read);
if (fd_write > 0) (void)close(fd_write); if (fd_write > 0) (void)close(fd_write);
if (!yield) if (!yield)
{ {
if (filter_pid > 0) kill(filter_pid, SIGKILL); if (filter_pid > 0) kill(filter_pid, SIGKILL);
if (write_pid > 0) kill(write_pid, SIGKILL); if (write_pid > 0) kill(write_pid, SIGKILL);
} }
skipping to change at line 1380 skipping to change at line 1382
} }
(void)close(pfd[pipe_read]); (void)close(pfd[pipe_read]);
/* If there have been no problems we can now add the terminating "." if this is /* If there have been no problems we can now add the terminating "." if this is
SMTP output, turning off escaping beforehand. If the last character from the SMTP output, turning off escaping beforehand. If the last character from the
filter was not NL, insert a NL to make the SMTP protocol work. */ filter was not NL, insert a NL to make the SMTP protocol work. */
if (yield) if (yield)
{ {
nl_check_length = nl_escape_length = 0; nl_check_length = nl_escape_length = 0;
spool_file_wireformat = FALSE; f.spool_file_wireformat = FALSE;
if ( tctx->options & topt_end_dot if ( tctx->options & topt_end_dot
&& ( last_filter_was_NL && ( last_filter_was_NL
? !write_chunk(tctx, US".\n", 2) ? !write_chunk(tctx, US".\n", 2)
: !write_chunk(tctx, US"\n.\n", 3) : !write_chunk(tctx, US"\n.\n", 3)
) ) ) )
yield = FALSE; yield = FALSE;
/* Write out any remaining data in the buffer. */ /* Write out any remaining data in the buffer. */
else else
skipping to change at line 1840 skipping to change at line 1842
const uschar *hostaddress, uschar *id, int socket_fd) const uschar *hostaddress, uschar *id, int socket_fd)
{ {
int i = 20; int i = 20;
const uschar **argv; const uschar **argv;
/* Set up the calling arguments; use the standard function for the basics, /* Set up the calling arguments; use the standard function for the basics,
but we have a number of extras that may be added. */ but we have a number of extras that may be added. */
argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0); argv = CUSS child_exec_exim(CEE_RETURN_ARGV, TRUE, &i, FALSE, 0);
if (smtp_authenticated) argv[i++] = US"-MCA"; if (f.smtp_authenticated) argv[i++] = US"-MCA";
if (smtp_peer_options & OPTION_CHUNKING) argv[i++] = US"-MCK"; if (smtp_peer_options & OPTION_CHUNKING) argv[i++] = US"-MCK";
if (smtp_peer_options & OPTION_DSN) argv[i++] = US"-MCD"; if (smtp_peer_options & OPTION_DSN) argv[i++] = US"-MCD";
if (smtp_peer_options & OPTION_PIPE) argv[i++] = US"-MCP"; if (smtp_peer_options & OPTION_PIPE) argv[i++] = US"-MCP";
if (smtp_peer_options & OPTION_SIZE) argv[i++] = US"-MCS"; if (smtp_peer_options & OPTION_SIZE) argv[i++] = US"-MCS";
#ifdef SUPPORT_TLS #ifdef SUPPORT_TLS
if (smtp_peer_options & OPTION_TLS) if (smtp_peer_options & OPTION_TLS)
if (tls_out.active >= 0 || continue_proxy_cipher) if (tls_out.active.sock >= 0 || continue_proxy_cipher)
{ {
argv[i++] = US"-MCt"; argv[i++] = US"-MCt";
argv[i++] = sending_ip_address; argv[i++] = sending_ip_address;
argv[i++] = string_sprintf("%d", sending_port); argv[i++] = string_sprintf("%d", sending_port);
argv[i++] = tls_out.active >= 0 ? tls_out.cipher : continue_proxy_cipher; argv[i++] = tls_out.active.sock >= 0 ? tls_out.cipher : continue_proxy_ciphe r;
} }
else else
argv[i++] = US"-MCT"; argv[i++] = US"-MCT";
#endif #endif
if (queue_run_pid != (pid_t)0) if (queue_run_pid != (pid_t)0)
{ {
argv[i++] = US"-MCQ"; argv[i++] = US"-MCQ";
argv[i++] = string_sprintf("%d", queue_run_pid); argv[i++] = string_sprintf("%d", queue_run_pid);
argv[i++] = string_sprintf("%d", queue_run_pipe); argv[i++] = string_sprintf("%d", queue_run_pipe);
skipping to change at line 1924 skipping to change at line 1926
/* Disconnect entirely from the parent process. If we are running in the /* Disconnect entirely from the parent process. If we are running in the
test harness, wait for a bit to allow the previous process time to finish, test harness, wait for a bit to allow the previous process time to finish,
write the log, etc., so that the output is always in the same order for write the log, etc., so that the output is always in the same order for
automatic comparison. */ automatic comparison. */
if ((pid = fork()) != 0) if ((pid = fork()) != 0)
{ {
DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid); DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid);
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
if (running_in_test_harness) sleep(1); if (f.running_in_test_harness) sleep(1);
transport_do_pass_socket(transport_name, hostname, hostaddress, transport_do_pass_socket(transport_name, hostname, hostaddress,
id, socket_fd); id, socket_fd);
} }
/* If the process creation succeeded, wait for the first-level child, which /* If the process creation succeeded, wait for the first-level child, which
immediately exits, leaving the second level process entirely disconnected from immediately exits, leaving the second level process entirely disconnected from
this one. */ this one. */
if (pid > 0) if (pid > 0)
skipping to change at line 2213 skipping to change at line 2215
/* Subtract one since we replace $address_pipe */ /* Subtract one since we replace $address_pipe */
argcount--; argcount--;
i--; i--;
} }
/* Handle normal expansion string */ /* Handle normal expansion string */
else else
{ {
const uschar *expanded_arg; const uschar *expanded_arg;
enable_dollar_recipients = allow_dollar_recipients; f.enable_dollar_recipients = allow_dollar_recipients;
expanded_arg = expand_cstring(argv[i]); expanded_arg = expand_cstring(argv[i]);
enable_dollar_recipients = FALSE; f.enable_dollar_recipients = FALSE;
if (expanded_arg == NULL) if (expanded_arg == NULL)
{ {
uschar *msg = string_sprintf("Expansion of \"%s\" " uschar *msg = string_sprintf("Expansion of \"%s\" "
"from command \"%s\" in %s failed: %s", "from command \"%s\" in %s failed: %s",
argv[i], cmd, etext, expand_string_message); argv[i], cmd, etext, expand_string_message);
if (addr != NULL) if (addr != NULL)
{ {
addr->transport_return = expand_failed; addr->transport_return = expand_failed;
addr->message = msg; addr->message = msg;
 End of changes. 35 change blocks. 
34 lines changed or deleted 36 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)