* Exim - an Internet mail transport agent *
*************************************************/
-/* Copyright (c) The Exim Maintainers 2020 - 2022 */
+/* Copyright (c) The Exim Maintainers 2020 - 2023 */
/* Copyright (c) University of Cambridge 1995 - 2018 */
/* See the file NOTICE for conditions of use and distribution. */
/* SPDX-License-Identifier: GPL-2.0-or-later */
#endif
{ "hosts_require_helo", opt_stringptr, {&hosts_require_helo} },
{ "hosts_treat_as_local", opt_stringptr, {&hosts_treat_as_local} },
+#ifdef EXPERIMENTAL_XCLIENT
+ { "hosts_xclient", opt_stringptr, {&hosts_xclient} },
+#endif
#ifdef LOOKUP_IBASE
{ "ibase_servers", opt_stringptr, {&ibase_servers} },
#endif
{ "ldap_start_tls", opt_bool, {&eldap_start_tls} },
{ "ldap_version", opt_int, {&eldap_version} },
#endif
-#ifdef EXPERIMENTAL_ESMTP_LIMITS
+#ifndef DISABLE_ESMTP_LIMITS
{ "limits_advertise_hosts", opt_stringptr, {&limits_advertise_hosts} },
#endif
{ "local_from_check", opt_bool, {&local_from_check} },
{ "received_header_text", opt_stringptr, {&received_header_text} },
{ "received_headers_max", opt_int, {&received_headers_max} },
{ "recipient_unqualified_hosts", opt_stringptr, {&recipient_unqualified_hosts} },
- { "recipients_max", opt_int, {&recipients_max} },
+ { "recipients_max", opt_stringptr, {&recipients_max} },
{ "recipients_max_reject", opt_bool, {&recipients_max_reject} },
#ifdef LOOKUP_REDIS
{ "redis_servers", opt_stringptr, {&redis_servers} },
{ "uucp_from_pattern", opt_stringptr, {&uucp_from_pattern} },
{ "uucp_from_sender", opt_stringptr, {&uucp_from_sender} },
{ "warn_message_file", opt_stringptr, {&warn_message_file} },
- { "write_rejectlog", opt_bool, {&write_rejectlog} }
+ { "write_rejectlog", opt_bool, {&write_rejectlog} },
};
#ifndef MACRO_PREDEF
pointer variables in the options table or in option tables for various drivers.
For debugging output, it is useful to be able to find the name of the option
which is currently being processed. This function finds it, if it exists, by
-searching the table(s).
+searching the table(s) for a value with the given content.
Arguments: a value that is presumed to be in the table above
Returns: the option name, or an empty string
*/
-uschar *
-readconf_find_option(void *p)
+const uschar *
+readconf_find_option(void * listptr)
{
-for (int i = 0; i < nelem(optionlist_config); i++)
- if (p == optionlist_config[i].v.value) return US optionlist_config[i].name;
+uschar * list = * USS listptr;
+const uschar * name = NULL, * drname = NULL;
+
+for (optionlist * o = optionlist_config; /* main-config options */
+ o < optionlist_config + optionlist_config_size; o++)
+ if (listptr == o->v.value)
+ return US o->name;
for (router_instance * r = routers; r; r = r->next)
+ if (router_name && Ustrcmp(r->name, router_name) == 0)
{
- router_info *ri = r->info;
- for (int i = 0; i < *ri->options_count; i++)
- {
- if ((ri->options[i].type & opt_mask) != opt_stringptr) continue;
- if (p == CS (r->options_block) + ri->options[i].v.offset)
- return US ri->options[i].name;
- }
+ const router_info * ri = r->info;
+
+ /* Check for a listptr match first */
+
+ for (optionlist * o = optionlist_routers; /* generic options */
+ o < optionlist_routers + optionlist_routers_size; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && listptr == CS r + o->v.offset)
+ return US o->name;
+
+ for (optionlist * o = ri->options; /* private options */
+ o < ri->options + *ri->options_count; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && listptr == CS (r->options_block) + o->v.offset)
+ return US o->name;
+
+ /* Check for a list addr match, unless null */
+
+ if (!list) continue;
+
+ for (optionlist * o = optionlist_routers; /* generic options */
+ o < optionlist_routers + optionlist_routers_size; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && list == * USS(CS r + o->v.offset))
+ if (name) return string_sprintf("DUP: %s %s vs. %s %s",
+ drname, name, r->name, o->name);
+ else { name = US o->name; drname = r->name; }
+
+ for (optionlist * o = ri->options; /* private options */
+ o < ri->options + *ri->options_count; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && list == * USS(CS (r->options_block) + o->v.offset))
+ if (name) return string_sprintf("DUP: %s %s vs. %s %s",
+ drname, name, r->name, o->name);
+ else { name = US o->name; drname = r->name; }
}
for (transport_instance * t = transports; t; t = t->next)
+ if (transport_name && Ustrcmp(t->name, transport_name) == 0)
{
- transport_info *ti = t->info;
- for (int i = 0; i < *ti->options_count; i++)
- {
- optionlist * op = &ti->options[i];
- if ((op->type & opt_mask) != opt_stringptr) continue;
- if (p == ( op->type & opt_public
- ? CS t
- : CS t->options_block
- )
- + op->v.offset)
- return US op->name;
- }
+ const transport_info * ti = t->info;
+
+ /* Check for a listptr match first */
+
+ for (optionlist * o = optionlist_transports; /* generic options */
+ o < optionlist_transports + optionlist_transports_size; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && listptr == CS t + o->v.offset)
+ return US o->name;
+
+ for (optionlist * o = ti->options; /* private options */
+ o < ti->options + *ti->options_count; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && listptr == CS t->options_block + o->v.offset)
+ return US o->name;
+
+ /* Check for a list addr match, unless null */
+
+ if (!list) continue;
+
+ for (optionlist * o = optionlist_transports; /* generic options */
+ o < optionlist_transports + optionlist_transports_size; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && list == * USS(CS t + o->v.offset))
+ if (name) return string_sprintf("DUP: %s %s vs. %s %s",
+ drname, name, t->name, o->name);
+ else { name = US o->name; drname = t->name; }
+
+ for (optionlist * o = ti->options; /* private options */
+ o < ti->options + *ti->options_count; o++)
+ if ( (o->type & opt_mask) == opt_stringptr
+ && list == * USS(CS t->options_block + o->v.offset))
+ if (name) return string_sprintf("DUP: %s %s vs. %s %s",
+ drname, name, t->name, o->name);
+ else { name = US o->name; drname = t->name; }
}
-return US"";
+return name ? name : US"";
}
(Ustrncmp(ss+8, "_if_exists", 10) == 0 && isspace(ss[18]))))
{
uschar *t;
- int include_if_exists = isspace(ss[8])? 0 : 10;
+ int include_if_exists = isspace(ss[8]) ? 0 : 10;
config_file_item *save;
struct stat statbuf;
/* There may be leading spaces; thereafter, we expect an option name starting
with a letter. */
-while (isspace(*s)) s++;
-if (!isalpha(*s))
+if (!isalpha( Uskip_whitespace(&s) ))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "option setting expected: %s", s);
/* Read the name of the option, and skip any subsequent white space. If
s++;
}
name[ptr] = 0;
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);
if (Ustrcmp(name, "hide") != 0) break;
issecure = opt_secure;
ptr = 0;
/* Skip white space after = */
-if (*s == '=') while (isspace((*(++s))));
+if (*s == '=') while (isspace(*++s));
/* If there is a data block and the opt_public flag is not set, change
the data block pointer to the private options block. */
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"absolute value of integer \"%s\" is too large (overflow)", s);
- while (isspace(*endptr)) endptr++;
- if (*endptr)
+ if (Uskip_whitespace(&endptr))
extra_chars_error(endptr, inttype, US"integer value for ", name);
value = (int)lvalue;
if (errno == ERANGE) log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN,
"absolute value of integer \"%s\" is too large (overflow)", s);
- while (isspace(*endptr)) endptr++;
- if (*endptr != 0)
+ if (Uskip_whitespace(&endptr))
extra_chars_error(endptr, inttype, US"integer value for ", name);
if (data_block)
list[count+1] = value;
if (snext == NULL) break;
s = snext + 1;
- while (isspace(*s)) s++;
+ Uskip_whitespace(&s);
}
if (count > list[0] - 2)
}
case opt_func:
- {
- void (*fn)() = ol->v.fn;
- fn(name, s, 0);
+ ol->v.fn(name, s, 0);
break;
- }
}
return TRUE;
int s, m, h, d, w;
uschar *p = time_buffer;
-if (t < 0)
- {
- *p++ = '-';
- t = -t;
- }
+if (t < 0) *p++ = '-', t = -t;
s = t % 60;
t /= 60;
*/
BOOL
-readconf_print(const uschar *name, uschar *type, BOOL no_labels)
+readconf_print(const uschar * name, const uschar * type, BOOL no_labels)
{
BOOL names_only = FALSE;
optionlist *ol2 = NULL;
for printing. So we have an admin_users restriction. */
if (!f.admin_user)
{
- fprintf(stderr, "exim: permission denied\n");
+ fprintf(stderr, "exim: permission denied; not admin\n");
return FALSE;
}
for (macro_item * m = macros; m; m = m->next)
{
int sep = 0;
struct stat statbuf;
-uschar *s, *filename;
-const uschar *list = config_main_filelist;
+uschar * s, * filename;
+const uschar * list = config_main_filelist;
/* Loop through the possible file names */
if (syslog_facility_str)
{
int i;
- uschar *s = syslog_facility_str;
+ uschar * s = syslog_facility_str;
if ((Ustrlen(syslog_facility_str) >= 4) &&
(strncmpic(syslog_facility_str, US"log_", 4) == 0))
if (*pid_file_path)
{
- if (!(s = expand_string(pid_file_path)))
+ const uschar * t = expand_cstring(pid_file_path);
+ if (!t)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to expand pid_file_path "
"\"%s\": %s", pid_file_path, expand_string_message);
- pid_file_path = s;
+ pid_file_path = t;
}
/* Set default value of process_log_path */
"failed to expand localhost_number \"%s\": %s",
host_number_string, expand_string_message);
n = Ustrtol(s, &end, 0);
- while (isspace(*end)) end++;
- if (*end)
+ if (Uskip_whitespace(&end))
log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
"localhost_number value is not a number: %s", s);
if (n > LOCALHOST_MAX)
*/
static int
-retry_arg(const uschar **paddr, int type)
+retry_arg(const uschar ** paddr, int type)
{
-const uschar *p = *paddr;
-const uschar *pp;
+const uschar * p = *paddr, * pp;
if (*p++ != ',') log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "comma expected");
pp = p;
while (isalnum(*p) || (type == 1 && *p == '.')) p++;
-if (*p != 0 && !isspace(*p) && *p != ',' && *p != ';')
+if (*p && !isspace(*p) && *p != ',' && *p != ';')
log_write(0, LOG_PANIC_DIE|LOG_CONFIG_IN, "comma or semicolon expected");
*paddr = p;
r = store_mark();
/* skip over to the first non-space */
- for (current = string_copy(i->line); *current && isspace(*current); ++current)
- ;
-
- if (!*current)
+ current = string_copy(i->line);
+ if (!Uskip_whitespace(¤t))
continue;
/* Collapse runs of spaces. We stop this if we encounter one of the
for (p = current; *p; p++) if (isspace(*p))
{
- uschar *next;
+ uschar * next = p;
if (*p != ' ') *p = ' ';
- for (next = p; isspace(*next); ++next)
- ;
+ Uskip_whitespace(&p);
if (next - p > 1)
memmove(p+1, next, Ustrlen(next)+1);