data blocks and which therefore have the opt_public flag set. Note that there
are other options living inside this structure which can be set only from
certain transports. */
+#define LOFF(field) OPT_OFF(transport_instance, field)
optionlist optionlist_transports[] = {
/* name type value */
{ "*expand_group", opt_stringptr|opt_hidden|opt_public,
- (void *)offsetof(transport_instance, expand_gid) },
+ LOFF(expand_gid) },
{ "*expand_user", opt_stringptr|opt_hidden|opt_public,
- (void *)offsetof(transport_instance, expand_uid) },
+ LOFF(expand_uid) },
{ "*headers_rewrite_flags", opt_int|opt_public|opt_hidden,
- (void *)offsetof(transport_instance, rewrite_existflags) },
+ LOFF(rewrite_existflags) },
{ "*headers_rewrite_rules", opt_void|opt_public|opt_hidden,
- (void *)offsetof(transport_instance, rewrite_rules) },
+ LOFF(rewrite_rules) },
{ "*set_group", opt_bool|opt_hidden|opt_public,
- (void *)offsetof(transport_instance, gid_set) },
+ LOFF(gid_set) },
{ "*set_user", opt_bool|opt_hidden|opt_public,
- (void *)offsetof(transport_instance, uid_set) },
+ LOFF(uid_set) },
{ "body_only", opt_bool|opt_public,
- (void *)offsetof(transport_instance, body_only) },
+ LOFF(body_only) },
{ "current_directory", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, current_dir) },
+ LOFF(current_dir) },
{ "debug_print", opt_stringptr | opt_public,
- (void *)offsetof(transport_instance, debug_string) },
+ LOFF(debug_string) },
{ "delivery_date_add", opt_bool|opt_public,
- (void *)(offsetof(transport_instance, delivery_date_add)) },
+ LOFF(delivery_date_add) },
{ "disable_logging", opt_bool|opt_public,
- (void *)(offsetof(transport_instance, disable_logging)) },
+ LOFF(disable_logging) },
{ "driver", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, driver_name) },
+ LOFF(driver_name) },
{ "envelope_to_add", opt_bool|opt_public,
- (void *)(offsetof(transport_instance, envelope_to_add)) },
+ LOFF(envelope_to_add) },
#ifndef DISABLE_EVENT
{ "event_action", opt_stringptr | opt_public,
- (void *)offsetof(transport_instance, event_action) },
+ LOFF(event_action) },
#endif
{ "group", opt_expand_gid|opt_public,
- (void *)offsetof(transport_instance, gid) },
+ LOFF(gid) },
{ "headers_add", opt_stringptr|opt_public|opt_rep_str,
- (void *)offsetof(transport_instance, add_headers) },
+ LOFF(add_headers) },
{ "headers_only", opt_bool|opt_public,
- (void *)offsetof(transport_instance, headers_only) },
+ LOFF(headers_only) },
{ "headers_remove", opt_stringptr|opt_public|opt_rep_str,
- (void *)offsetof(transport_instance, remove_headers) },
+ LOFF(remove_headers) },
{ "headers_rewrite", opt_rewrite|opt_public,
- (void *)offsetof(transport_instance, headers_rewrite) },
+ LOFF(headers_rewrite) },
{ "home_directory", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, home_dir) },
+ LOFF(home_dir) },
{ "initgroups", opt_bool|opt_public,
- (void *)offsetof(transport_instance, initgroups) },
+ LOFF(initgroups) },
{ "max_parallel", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, max_parallel) },
+ LOFF(max_parallel) },
{ "message_size_limit", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, message_size_limit) },
+ LOFF(message_size_limit) },
{ "rcpt_include_affixes", opt_bool|opt_public,
- (void *)offsetof(transport_instance, rcpt_include_affixes) },
+ LOFF(rcpt_include_affixes) },
{ "retry_use_local_part", opt_bool|opt_public,
- (void *)offsetof(transport_instance, retry_use_local_part) },
+ LOFF(retry_use_local_part) },
{ "return_path", opt_stringptr|opt_public,
- (void *)(offsetof(transport_instance, return_path)) },
+ LOFF(return_path) },
{ "return_path_add", opt_bool|opt_public,
- (void *)(offsetof(transport_instance, return_path_add)) },
+ LOFF(return_path_add) },
{ "shadow_condition", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, shadow_condition) },
+ LOFF(shadow_condition) },
{ "shadow_transport", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, shadow) },
+ LOFF(shadow) },
{ "transport_filter", opt_stringptr|opt_public,
- (void *)offsetof(transport_instance, filter_command) },
+ LOFF(filter_command) },
{ "transport_filter_timeout", opt_time|opt_public,
- (void *)offsetof(transport_instance, filter_timeout) },
+ LOFF(filter_timeout) },
{ "user", opt_expand_uid|opt_public,
- (void *)offsetof(transport_instance, uid) }
+ LOFF(uid) }
};
int optionlist_transports_size = nelem(optionlist_transports);
}
else /* Timeout wanted. */
{
+ sigalrm_seen = FALSE;
ALARM(local_timeout);
rc = tpt_write(fd, block, len, more, tctx->options);
save_errno = errno;
return addr->address;
}
-if (addr->suffix == NULL)
+if (!addr->suffix)
{
- if (addr->prefix == NULL) return addr->address;
+ if (!addr->prefix) return addr->address;
return addr->address + Ustrlen(addr->prefix);
}
at = Ustrrchr(addr->address, '@');
-plen = (addr->prefix == NULL)? 0 : Ustrlen(addr->prefix);
+plen = addr->prefix ? Ustrlen(addr->prefix) : 0;
slen = Ustrlen(addr->suffix);
return string_sprintf("%.*s@%s", (int)(at - addr->address - plen - slen),
return FALSE;
}
len = s ? Ustrlen(s) : 0;
- if (strncmpic(h->text, s, len) != 0) continue;
- ss = h->text + len;
- while (*ss == ' ' || *ss == '\t') ss++;
- if (*ss == ':') break;
+ if (len && s[len-1] == '*') /* trailing glob */
+ {
+ if (strncmpic(h->text, s, len-1) == 0) break;
+ }
+ else
+ {
+ if (strncmpic(h->text, s, len) != 0) continue;
+ ss = h->text + len;
+ while (*ss == ' ' || *ss == '\t') ss++;
+ if (*ss == ':') break;
+ }
}
if (s) { include_header = FALSE; break; }
}
{
BOOL last_filter_was_NL = TRUE;
BOOL save_spool_file_wireformat = f.spool_file_wireformat;
-int rc, len, yield, fd_read, fd_write, save_errno;
+BOOL yield;
+int rc, len, fd_read, fd_write, save_errno;
int pfd[2] = {-1, -1};
pid_t filter_pid, write_pid;
{
int bits = fcntl(tctx->u.fd, F_GETFD);
- (void)fcntl(tctx->u.fd, F_SETFD, bits | FD_CLOEXEC);
+ (void) fcntl(tctx->u.fd, F_SETFD, bits | FD_CLOEXEC);
filter_pid = child_open(USS transport_filter_argv, NULL, 077,
- &fd_write, &fd_read, FALSE);
- (void)fcntl(tctx->u.fd, F_SETFD, bits & ~FD_CLOEXEC);
+ &fd_write, &fd_read, FALSE, US"transport-filter");
+ (void) fcntl(tctx->u.fd, F_SETFD, bits & ~FD_CLOEXEC);
}
if (filter_pid < 0) goto TIDY_UP; /* errno set */
smtp dots, or check string processing. */
if (pipe(pfd) != 0) goto TIDY_UP; /* errno set */
-if ((write_pid = fork()) == 0)
+if ((write_pid = exim_fork(US"tpt-filter-writer")) == 0)
{
BOOL rc;
(void)close(fd_read);
!= sizeof(int)
|| write(pfd[pipe_write], (void *)&tctx->addr->more_errno, sizeof(int))
!= sizeof(int)
- || write(pfd[pipe_write], (void *)&tctx->addr->delivery_usec, sizeof(int))
- != sizeof(int)
+ || write(pfd[pipe_write], (void *)&tctx->addr->delivery_time, sizeof(struct timeval))
+ != sizeof(struct timeval)
)
rc = FALSE; /* compiler quietening */
- exim_underbar_exit(0);
+ exim_underbar_exit(EXIT_SUCCESS);
}
save_errno = errno;
ALARM_CLR(0);
if (sigalrm_seen)
{
+ DEBUG(D_transport) debug_printf("timed out reading from filter\n");
errno = ETIMEDOUT;
f.transport_filter_timed_out = TRUE;
goto TIDY_UP;
{
int dummy = read(pfd[pipe_read], (void *)&save_errno, sizeof(int));
dummy = read(pfd[pipe_read], (void *)&tctx->addr->more_errno, sizeof(int));
- dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_usec, sizeof(int));
+ dummy = read(pfd[pipe_read], (void *)&tctx->addr->delivery_time, sizeof(struct timeval));
dummy = dummy; /* compiler quietening */
yield = FALSE;
}
{
debug_printf("end of filtering transport writing: yield=%d\n", yield);
if (!yield)
- debug_printf("errno=%d more_errno=%d\n", errno, tctx->addr->more_errno);
+ debug_printf(" errno=%d more_errno=%d\n", errno, tctx->addr->more_errno);
}
return yield;
/* If this record is full, write it out with a new name constructed
from the sequence number, increase the sequence number, and empty
- the record. */
+ the record. If we're doing a two-phase queue run initial phase, ping the
+ daemon to consider running a delivery on this host. */
if (host_record->count >= WAIT_NAME_MAX)
{
sprintf(CS buffer, "%.200s:%d", host->name, host_record->sequence);
dbfn_write(dbm_file, buffer, host_record, sizeof(dbdata_wait) + host_length);
+#ifdef EXPERIMENTAL_QUEUE_RAMP
+ if (f.queue_2stage && queue_fast_ramp && !queue_run_in_order)
+ queue_notify_daemon(message_id);
+#endif
host_record->sequence++;
host_record->count = 0;
host_length = 0;
}
/* first thing remove current message id if it exists */
+ /*XXX but what if it has un-sent addrs? */
for (i = 0; i < msgq_count; ++i)
if (Ustrcmp(msgq[i].message_id, message_id) == 0)
DEBUG(D_transport) debug_printf("transport_pass_socket entered\n");
-if ((pid = fork()) == 0)
+if ((pid = exim_fork(US"continued-transport-interproc")) == 0)
{
/* 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,
write the log, etc., so that the output is always in the same order for
automatic comparison. */
- if ((pid = fork()) != 0)
- {
- DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (final-pid %d)\n", pid);
+ if ((pid = exim_fork(US"continued-transport")) != 0)
_exit(EXIT_SUCCESS);
- }
testharness_pause_ms(1000);
transport_do_pass_socket(transport_name, hostname, hostaddress,
{
int rc;
while ((rc = wait(&status)) != pid && (rc >= 0 || errno != ECHILD));
- DEBUG(D_transport) debug_printf("transport_pass_socket succeeded (inter-pid %d)\n", pid);
return TRUE;
}
else