* Exim - an Internet mail transport agent *
*************************************************/
+/* Copyright (c) The Exim Maintainers 2020 - 2022 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
-/* Copyright (c) The Exim Maintainers 2020 */
/* See the file NOTICE for conditions of use and distribution. */
/* Functions for reading the configuration file, and for displaying
#ifdef SUPPORT_PROXY
{ "hosts_proxy", opt_stringptr, {&hosts_proxy} },
#endif
+#ifndef DISABLE_TLS
+ { "hosts_require_alpn", opt_stringptr, {&hosts_require_alpn} },
+#endif
+ { "hosts_require_helo", opt_stringptr, {&hosts_require_helo} },
{ "hosts_treat_as_local", opt_stringptr, {&hosts_treat_as_local} },
#ifdef LOOKUP_IBASE
{ "ibase_servers", opt_stringptr, {&ibase_servers} },
{ "ldap_require_cert", opt_stringptr, {&eldap_require_cert} },
{ "ldap_start_tls", opt_bool, {&eldap_start_tls} },
{ "ldap_version", opt_int, {&eldap_version} },
+#endif
+#ifdef EXPERIMENTAL_ESMTP_LIMITS
+ { "limits_advertise_hosts", opt_stringptr, {&limits_advertise_hosts} },
#endif
{ "local_from_check", opt_bool, {&local_from_check} },
{ "local_from_prefix", opt_stringptr, {&local_from_prefix} },
{ "smtp_accept_max", opt_int, {&smtp_accept_max} },
{ "smtp_accept_max_nonmail", opt_int, {&smtp_accept_max_nonmail} },
{ "smtp_accept_max_nonmail_hosts", opt_stringptr, {&smtp_accept_max_nonmail_hosts} },
- { "smtp_accept_max_per_connection", opt_int, {&smtp_accept_max_per_connection} },
+ { "smtp_accept_max_per_connection", opt_stringptr, {&smtp_accept_max_per_connection} },
{ "smtp_accept_max_per_host", opt_stringptr, {&smtp_accept_max_per_host} },
{ "smtp_accept_queue", opt_int, {&smtp_accept_queue} },
{ "smtp_accept_queue_per_connection", opt_int, {&smtp_accept_queue_per_connection} },
{ "smtp_accept_reserve", opt_int, {&smtp_accept_reserve} },
{ "smtp_active_hostname", opt_stringptr, {&raw_active_hostname} },
+ { "smtp_backlog_monitor", opt_int, {&smtp_backlog_monitor} },
{ "smtp_banner", opt_stringptr, {&smtp_banner} },
{ "smtp_check_spool_space", opt_bool, {&smtp_check_spool_space} },
{ "smtp_connect_backlog", opt_int, {&smtp_connect_backlog} },
#ifdef LOOKUP_SQLITE
{ "sqlite_dbfile", opt_stringptr, {&sqlite_dbfile} },
{ "sqlite_lock_timeout", opt_int, {&sqlite_lock_timeout} },
-#endif
-#ifdef EXPERIMENTAL_SRS_ALT
- { "srs_config", opt_stringptr, {&srs_config} },
- { "srs_hashlength", opt_int, {&srs_hashlength} },
- { "srs_hashmin", opt_int, {&srs_hashmin} },
- { "srs_maxage", opt_int, {&srs_maxage} },
- { "srs_secrets", opt_stringptr, {&srs_secrets} },
- { "srs_usehash", opt_bool, {&srs_usehash} },
- { "srs_usetimestamp", opt_bool, {&srs_usetimestamp} },
#endif
{ "strict_acl_vars", opt_bool, {&strict_acl_vars} },
{ "strip_excess_angle_brackets", opt_bool, {&strip_excess_angle_brackets} },
{ "timezone", opt_stringptr, {&timezone_string} },
{ "tls_advertise_hosts", opt_stringptr, {&tls_advertise_hosts} },
#ifndef DISABLE_TLS
+ { "tls_alpn", opt_stringptr, {&tls_alpn} },
{ "tls_certificate", opt_stringptr, {&tls_certificate} },
{ "tls_crl", opt_stringptr, {&tls_crl} },
{ "tls_dh_max_bits", opt_int, {&tls_dh_max_bits} },
void
options_auths(void)
{
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];
options_from_list(optionlist_auths, optionlist_auths_size, US"AUTHENTICATORS", NULL);
void
options_logging(void)
{
-uschar buf[64];
+uschar buf[EXIM_DRIVERNAME_MAX];
for (bit_table * bp = log_options; bp < log_options + log_options_count; bp++)
{
macro_item *
macro_create(const uschar * name, const uschar * val, BOOL command_line)
{
-macro_item * m = store_get(sizeof(macro_item), FALSE);
+macro_item * m = store_get(sizeof(macro_item), GET_UNTAINTED);
READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
m->next = NULL;
BOOL
macro_read_assignment(uschar *s)
{
-uschar name[64];
+uschar name[EXIM_DRIVERNAME_MAX];
int namelen = 0;
BOOL redef = FALSE;
macro_item *m;
if (config_lines)
save_config_position(config_filename, config_lineno);
- save = store_get(sizeof(config_file_item), FALSE);
+ save = store_get(sizeof(config_file_item), GET_UNTAINTED);
save->next = config_file_stack;
config_file_stack = save;
save->file = config_file;
readconf_readname(uschar *name, int len, uschar *s)
{
int p = 0;
+BOOL broken = FALSE;
if (isalpha(Uskip_whitespace(&s)))
while (isalnum(*s) || *s == '_')
{
if (p < len-1) name[p++] = *s;
+ else {
+ broken = TRUE;
+ break;
+ }
s++;
}
name[p] = 0;
+if (broken) {
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
+ "exim item name too long (>%d), unable to use \"%s\" (truncated)",
+ len, name);
+}
Uskip_whitespace(&s);
return s;
}
*/
static optionlist *
-find_option(uschar *name, optionlist *ol, int last)
+find_option(const uschar *name, optionlist *ol, int last)
{
int first = 0;
while (last > first)
*/
static BOOL *
-get_set_flag(uschar *name, optionlist *oltop, int last, void *data_block)
+get_set_flag(const uschar *name, optionlist *oltop, int last, void *data_block)
{
optionlist *ol;
-uschar name2[64];
+uschar name2[EXIM_DRIVERNAME_MAX];
sprintf(CS name2, "*set_%.50s", name);
if (!(ol = find_option(name2, oltop, last)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE,
static rewrite_rule *
readconf_one_rewrite(const uschar *p, int *existflags, BOOL isglobal)
{
-rewrite_rule *next = store_get(sizeof(rewrite_rule), FALSE);
+rewrite_rule * next = store_get(sizeof(rewrite_rule), GET_UNTAINTED);
next->next = NULL;
next->key = string_dequote(&p);
uschar *sptr;
uschar *s = buffer;
uschar **str_target;
-uschar name[64];
-uschar name2[64];
+uschar name[EXIM_DRIVERNAME_MAX];
+uschar name2[EXIM_DRIVERNAME_MAX];
/* There may be leading spaces; thereafter, we expect an option name starting
with a letter. */
case opt_bool_set:
if (*s != 0)
{
- s = readconf_readname(name2, 64, s);
+ s = readconf_readname(name2, EXIM_DRIVERNAME_MAX, s);
if (strcmpic(name2, US"true") == 0 || strcmpic(name2, US"yes") == 0)
boolvalue = TRUE;
else if (strcmpic(name2, US"false") == 0 || strcmpic(name2, US"no") == 0)
*/
static BOOL
-print_ol(optionlist *ol, uschar *name, void *options_block,
+print_ol(optionlist *ol, const uschar *name, void *options_block,
optionlist *oltop, int last, BOOL no_labels)
{
struct passwd *pw;
uid_t *uidlist;
gid_t *gidlist;
uschar *s;
-uschar name2[64];
+uschar name2[EXIM_DRIVERNAME_MAX];
if (!ol)
{
*/
BOOL
-readconf_print(uschar *name, uschar *type, BOOL no_labels)
+readconf_print(const uschar *name, uschar *type, BOOL no_labels)
{
BOOL names_only = FALSE;
optionlist *ol2 = NULL;
else
return print_ol(find_option(name,
- optionlist_config, nelem(optionlist_config)),
+ optionlist_config, nelem(optionlist_config)),
name, NULL, optionlist_config, nelem(optionlist_config), no_labels);
}
BOOL forcecache = FALSE;
uschar *ss;
tree_node *t;
-namedlist_block * nb = store_get(sizeof(namedlist_block), FALSE);
+namedlist_block * nb = store_get_perm(sizeof(namedlist_block), FALSE);
if (Ustrncmp(s, "_cache", 6) == 0)
{
Uskip_whitespace(&s);
ss = s;
while (isalnum(*s) || *s == '_') s++;
-t = store_get(sizeof(tree_node) + s-ss, is_tainted(ss));
+t = store_get(sizeof(tree_node) + s-ss, ss);
Ustrncpy(t->name, ss, s-ss);
t->name[s-ss] = 0;
Uskip_whitespace(&s);
/* Cut out all the fancy processing unless specifically wanted */
- #if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
+#if defined(CONFIGURE_FILE_USE_NODE) || defined(CONFIGURE_FILE_USE_EUID)
uschar *suffix = filename + Ustrlen(filename);
/* Try for the node-specific file if a node name exists */
- #ifdef CONFIGURE_FILE_USE_NODE
+# ifdef CONFIGURE_FILE_USE_NODE
struct utsname uts;
if (uname(&uts) >= 0)
{
- #ifdef CONFIGURE_FILE_USE_EUID
+# ifdef CONFIGURE_FILE_USE_EUID
sprintf(CS suffix, ".%ld.%.256s", (long int)original_euid, uts.nodename);
- config_file = Ufopen(filename, "rb");
- if (config_file == NULL)
- #endif /* CONFIGURE_FILE_USE_EUID */
+ if (!(config_file = Ufopen(filename, "rb")))
+# endif /* CONFIGURE_FILE_USE_EUID */
{
sprintf(CS suffix, ".%.256s", uts.nodename);
config_file = Ufopen(filename, "rb");
}
}
- #endif /* CONFIGURE_FILE_USE_NODE */
+# endif /* CONFIGURE_FILE_USE_NODE */
/* Otherwise, try the generic name, possibly with the euid added */
- #ifdef CONFIGURE_FILE_USE_EUID
- if (config_file == NULL)
+# ifdef CONFIGURE_FILE_USE_EUID
+ if (!config_file)
{
sprintf(CS suffix, ".%ld", (long int)original_euid);
config_file = Ufopen(filename, "rb");
}
- #endif /* CONFIGURE_FILE_USE_EUID */
+# endif /* CONFIGURE_FILE_USE_EUID */
/* Finally, try the unadorned name */
- if (config_file == NULL)
+ if (!config_file)
{
*suffix = 0;
config_file = Ufopen(filename, "rb");
}
- #else /* if neither defined */
+#else /* if neither defined */
/* This is the common case when the fancy processing is not included. */
config_file = Ufopen(filename, "rb");
- #endif
+#endif
/* If the file does not exist, continue to try any others. For any other
error, break out (and die). */
- if (config_file != NULL || errno != ENOENT) break;
+ if (config_file || errno != ENOENT) break;
}
/* On success, save the name for verification; config_filename is used when
config_main_directory = last_slash == filename ? US"/" : string_copyn(filename, last_slash - filename);
else
{
- /* relative configuration file name: working dir + / + basename(filename) */
+ /* relative configuration file name: working dir + / + basename(filename) */
- uschar buf[PATH_MAX];
- gstring * g;
+ uschar buf[PATH_MAX];
+ gstring * g;
- if (os_getcwd(buf, PATH_MAX) == NULL)
- {
- perror("exim: getcwd");
- exit(EXIT_FAILURE);
- }
- g = string_cat(NULL, buf);
+ if (os_getcwd(buf, PATH_MAX) == NULL)
+ {
+ perror("exim: getcwd");
+ exit(EXIT_FAILURE);
+ }
+ g = string_cat(NULL, buf);
- /* If the dir does not end with a "/", append one */
- if (g->s[g->ptr-1] != '/')
- g = string_catn(g, US"/", 1);
+ /* If the dir does not end with a "/", append one */
+ if (g->s[g->ptr-1] != '/')
+ g = string_catn(g, US"/", 1);
- /* If the config file contains a "/", extract the directory part */
- if (last_slash)
- g = string_catn(g, filename, last_slash - filename);
+ /* If the config file contains a "/", extract the directory part */
+ if (last_slash)
+ g = string_catn(g, filename, last_slash - filename);
- config_main_directory = string_from_gstring(g);
+ config_main_directory = string_from_gstring(g);
}
config_directory = config_main_directory;
}
else
- {
if (!filename)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "non-existent configuration file(s): "
"%s", config_main_filelist);
else
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "%s",
string_open_failed("configuration file %s", filename));
- }
/* Now, once we found and opened our configuration file, we change the directory
to a safe place. Later we change to $spool_directory. */
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
big_buffer);
- if ((statbuf.st_uid != root_uid /* owner not root */
- #ifdef CONFIGURE_OWNER
- && statbuf.st_uid != config_uid /* owner not the special one */
- #endif
- ) || /* or */
- (statbuf.st_gid != root_gid /* group not root & */
- #ifdef CONFIGURE_GROUP
- && statbuf.st_gid != config_gid /* group not the special one */
- #endif
- && (statbuf.st_mode & 020) != 0) || /* group writeable */
- /* or */
- ((statbuf.st_mode & 2) != 0)) /* world writeable */
-
+ if ( statbuf.st_uid != root_uid /* owner not root */
+#ifdef CONFIGURE_OWNER
+ && statbuf.st_uid != config_uid /* owner not the special one */
+#endif
+ || /* or */
+ statbuf.st_gid != root_gid /* group not root & */
+#ifdef CONFIGURE_GROUP
+ && statbuf.st_gid != config_gid /* group not the special one */
+#endif
+ && (statbuf.st_mode & 020) != 0 /* group writeable */
+ || /* or */
+ (statbuf.st_mode & 2) != 0 /* world writeable */
+ )
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "Exim configuration file %s has the "
"wrong owner, group, or mode", big_buffer);
if (statbuf.st_size > 8192)
{
rmark r = store_mark();
- void * dummy = store_get((int)statbuf.st_size, FALSE);
+ void * dummy = store_get((int)statbuf.st_size, GET_UNTAINTED);
store_reset(r);
}
}
read_named_list(&hostlist_anchor, &hostlist_count,
MAX_NAMED_LIST, t+8, US"host list", hide);
- else if (Ustrncmp(t, US"addresslist", 11) == 0)
+ else if (Ustrncmp(t, "addresslist", 11) == 0)
read_named_list(&addresslist_anchor, &addresslist_count,
MAX_NAMED_LIST, t+11, US"address list", hide);
- else if (Ustrncmp(t, US"localpartlist", 13) == 0)
+ else if (Ustrncmp(t, "localpartlist", 13) == 0)
read_named_list(&localpartlist_anchor, &localpartlist_count,
MAX_NAMED_LIST, t+13, US"local part list", hide);
/* If the timezone string is empty, set it to NULL, implying no TZ variable
wanted. */
-if (timezone_string != NULL && *timezone_string == 0) timezone_string = NULL;
+if (timezone_string && !*timezone_string) timezone_string = NULL;
/* The max retry interval must not be greater than 24 hours. */
canonize it. Some people like upper case letters in their host names, so we
don't force the case. */
-if (primary_hostname == NULL)
+if (!primary_hostname)
{
- const uschar *hostname;
+ const uschar * hostname;
struct utsname uts;
+
if (uname(&uts) < 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "uname() failed to yield host name");
hostname = US uts.nodename;
int af = AF_INET;
struct hostent *hostdata;
- #if HAVE_IPV6
- if (!disable_ipv6 && (dns_ipv4_lookup == NULL ||
- match_isinlist(hostname, CUSS &dns_ipv4_lookup, 0, NULL, NULL,
+#if HAVE_IPV6
+ if ( !disable_ipv6
+ && ( !dns_ipv4_lookup
+ || match_isinlist(hostname, CUSS &dns_ipv4_lookup, 0, NULL, NULL,
MCL_DOMAIN, TRUE, NULL) != OK))
af = AF_INET6;
- #else
- af = AF_INET;
- #endif
+#endif
for (;;)
{
- #if HAVE_IPV6
- #if HAVE_GETIPNODEBYNAME
+#if HAVE_IPV6
+# if HAVE_GETIPNODEBYNAME
int error_num;
hostdata = getipnodebyname(CS hostname, af, 0, &error_num);
#else
hostdata = gethostbyname2(CS hostname, af);
- #endif
- #else
+# endif
+#else
hostdata = gethostbyname(CS hostname);
- #endif
+#endif
- if (hostdata != NULL)
- {
- hostname = US hostdata->h_name;
- break;
- }
+ if (hostdata)
+ { hostname = US hostdata->h_name; break; }
if (af == AF_INET) break;
af = AF_INET;
/* Expand pid_file_path */
-if (*pid_file_path != 0)
+if (*pid_file_path)
{
if (!(s = expand_string(pid_file_path)))
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path "
/* Set default value of process_log_path */
-if (!process_log_path || *process_log_path =='\0')
+if (!process_log_path || !*process_log_path)
process_log_path = string_sprintf("%s/exim-process.info", spool_directory);
/* Compile the regex for matching a UUCP-style "From_" line in an incoming
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"error in errors_reply_to (%s): %s", errors_reply_to, errmess);
- if (domain == 0)
+ if (!domain)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"errors_reply_to (%s) does not contain a domain", errors_reply_to);
}
/* If smtp_accept_queue or smtp_accept_max_per_host is set, then
smtp_accept_max must also be set. */
-if (smtp_accept_max == 0 &&
- (smtp_accept_queue > 0 || smtp_accept_max_per_host != NULL))
+if (smtp_accept_max == 0 && (smtp_accept_queue > 0 || smtp_accept_max_per_host))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"smtp_accept_max must be set if smtp_accept_queue or "
"smtp_accept_max_per_host is set");
host_number_string, expand_string_message);
n = Ustrtol(s, &end, 0);
while (isspace(*end)) end++;
- if (*end != 0)
+ if (*end)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"localhost_number value is not a number: %s", s);
if (n > LOCALHOST_MAX)
{
int len = dd->options_len;
d->info = dd;
- d->options_block = store_get(len, FALSE);
+ d->options_block = store_get_perm(len, FALSE);
memcpy(d->options_block, dd->options_block, len);
for (int i = 0; i < *(dd->options_count); i++)
dd->options[i].type &= ~opt_set;
+static void
+driver_init_fini(driver_instance * d, const uschar * class)
+{
+if (!d->driver_name)
+ log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
+ "no driver defined for %s \"%s\"", class, d->name);
+(d->info->init)(d);
+}
+
+
/*************************************************
* Initialize driver list *
*************************************************/
while ((buffer = get_config_line()))
{
- uschar name[64];
+ uschar name[EXIM_DRIVERNAME_MAX];
uschar *s;
/* Read the first name on the line and test for the start of a new driver. A
{
if (d)
{
- if (!d->driver_name)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "no driver defined for %s \"%s\"", class, d->name);
/* s is using big_buffer, so this call had better not */
- (d->info->init)(d);
+ driver_init_fini(d, class);
d = NULL;
}
if (!macro_read_assignment(buffer)) exim_exit(EXIT_FAILURE);
/* Finish off initializing the previous driver. */
if (d)
- {
- if (!d->driver_name)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "no driver defined for %s \"%s\"", class, d->name);
- (d->info->init)(d);
- }
+ driver_init_fini(d, class);
/* Check that we haven't already got a driver of this name */
/* Set up a new driver instance data block on the chain, with
its default values installed. */
- d = store_get(instance_size, FALSE);
+ d = store_get_perm(instance_size, FALSE);
memcpy(d, instance_default, instance_size);
*p = d;
p = &d->next;
d->name = string_copy(name);
+ d->srcfile = config_filename;
+ d->srcline = config_lineno;
/* Clear out the "set" bits in the generic options */
/* Run the initialization function for the final driver. */
if (d)
- {
- if (!d->driver_name)
- log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
- "no driver defined for %s \"%s\"", class, d->name);
- (d->info->init)(d);
- }
+ driver_init_fini(d, class);
}
const uschar *pp;
uschar *error;
- next = store_get(sizeof(retry_config), FALSE);
+ next = store_get(sizeof(retry_config), GET_UNTAINTED);
next->next = NULL;
*chain = next;
chain = &(next->next);
while (*p)
{
- retry_rule *rule = store_get(sizeof(retry_rule), FALSE);
+ retry_rule * rule = store_get(sizeof(retry_rule), GET_UNTAINTED);
*rchain = rule;
rchain = &(rule->next);
rule->next = NULL;
for (auth_instance * bu = au->next; bu; bu = bu->next)
if (strcmpic(au->public_name, bu->public_name) == 0)
- if ((au->client && bu->client) || (au->server && bu->server))
+ if ( au->client && bu->client
+ || au->server && bu->server)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG, "two %s authenticators "
"(%s and %s) have the same public name (%s)",
- au->client ? US"client" : US"server", au->name, bu->name,
- au->public_name);
+ au->client && bu->client ? US"client" : US"server",
+ au->name, bu->name, au->public_name);
#ifndef DISABLE_PIPE_CONNECT
nauths++;
#endif
}
+/* For error messages, a string describing the config location associated
+with current processing. NULL if we are not in an authenticator. */
+
+uschar *
+authenticator_current_name(void)
+{
+if (!authenticator_name) return NULL;
+return string_sprintf(" (authenticator %s, %s %d)", authenticator_name, driver_srcfile, driver_srcline);
+}
+
+
+
/*************************************************
while(acl_line)
{
- uschar name[64];
+ uschar name[EXIM_DRIVERNAME_MAX];
tree_node *node;
uschar *error;
if (*p != ':' || name[0] == 0)
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "missing or malformed ACL name");
- node = store_get(sizeof(tree_node) + Ustrlen(name), is_tainted(name));
+ node = store_get_perm(sizeof(tree_node) + Ustrlen(name), name);
Ustrcpy(node->name, name);
if (!tree_insertnode(&acl_anchor, node))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
static config_line_item *current;
config_line_item *next;
-next = (config_line_item*) store_get(sizeof(config_line_item), FALSE);
+next = (config_line_item*) store_get(sizeof(config_line_item), GET_UNTAINTED);
next->line = string_copy(line);
next->next = NULL;
{
const int TS = terse ? 0 : 2;
int indent = 0;
+rmark r = NULL;
-for (config_line_item * i = config_lines; i; i = i->next)
+for (const config_line_item * i = config_lines; i; i = i->next)
{
- uschar *current;
- uschar *p;
+ uschar * current, * p;
+
+ if (r) store_reset(r);
+ r = store_mark();
/* skip over to the first non-space */
- for (current = i->line; *current && isspace(*current); ++current)
+ for (current = string_copy(i->line); *current && isspace(*current); ++current)
;
- if (*current == '\0')
+ if (!*current)
continue;
/* Collapse runs of spaces. We stop this if we encounter one of the
- * following characters: "'$, as this may indicate careful formatting */
- for (p = current; *p; ++p)
+ following characters: "'$, as this may indicate careful formatting */
+
+ for (p = current; *p; p++) if (isspace(*p))
{
uschar *next;
- if (!isspace(*p)) continue;
if (*p != ' ') *p = ' ';
for (next = p; isspace(*next); ++next)
/* rest is public */
printf("%*s%s\n", indent, "", current);
}
+if (r) store_reset(r);
}
#endif /*!MACRO_PREDEF*/