# include "macro_predef.h"
#endif
+#define READCONF_DEBUG if (FALSE) /* Change to TRUE to enable */
+
+
static uschar * syslog_facility_str;
static void fn_smtp_receive_timeout(const uschar *, const uschar *);
#endif
{ "dns_again_means_nonexist", opt_stringptr, &dns_again_means_nonexist },
{ "dns_check_names_pattern", opt_stringptr, &check_dns_names_pattern },
+ { "dns_cname_loops", opt_int, &dns_cname_loops },
{ "dns_csa_search_limit", opt_int, &dns_csa_search_limit },
{ "dns_csa_use_reverse", opt_bool, &dns_csa_use_reverse },
{ "dns_dnssec_ok", opt_int, &dns_dnssec_ok },
{ "local_from_prefix", opt_stringptr, &local_from_prefix },
{ "local_from_suffix", opt_stringptr, &local_from_suffix },
{ "local_interfaces", opt_stringptr, &local_interfaces },
+#ifdef HAVE_LOCAL_SCAN
{ "local_scan_timeout", opt_time, &local_scan_timeout },
+#endif
{ "local_sender_retain", opt_bool, &local_sender_retain },
{ "localhost_number", opt_stringptr, &host_number_string },
{ "log_file_path", opt_stringptr, &log_file_path },
{ "timezone", opt_stringptr, &timezone_string },
{ "tls_advertise_hosts", opt_stringptr, &tls_advertise_hosts },
#ifdef SUPPORT_TLS
+# ifdef EXPERIMENTAL_REQUIRETLS
+ { "tls_advertise_requiretls", opt_stringptr, &tls_advertise_requiretls },
+# endif
{ "tls_certificate", opt_stringptr, &tls_certificate },
{ "tls_crl", opt_stringptr, &tls_crl },
{ "tls_dh_max_bits", opt_int, &tls_dh_max_bits },
}
}
+void
+options_logging(void)
+{
+bit_table * bp;
+uschar buf[64];
+
+for (bp = log_options; bp < log_options + log_options_count; bp++)
+ {
+ spf(buf, sizeof(buf), US"_LOG_%T", bp->name);
+ builtin_macro_create(buf);
+ }
+}
+
#else /*!MACRO_PREDEF*/
+/*************************************************
+* Deal with an assignment to a macro *
+*************************************************/
+
+/* We have a new definition; append to the list.
+
+Args:
+ name Name of the macro; will be copied
+ val Expansion result for the macro; will be copied
+*/
+
+macro_item *
+macro_create(const uschar * name, const uschar * val, BOOL command_line)
+{
+macro_item * m = store_get(sizeof(macro_item));
+
+READCONF_DEBUG fprintf(stderr, "%s: '%s' '%s'\n", __FUNCTION__, name, val);
+m->next = NULL;
+m->command_line = command_line;
+m->namelen = Ustrlen(name);
+m->replen = Ustrlen(val);
+m->name = string_copy(name);
+m->replacement = string_copy(val);
+if (mlast)
+ mlast->next = m;
+else
+ macros = m;
+mlast = m;
+if (!macros_user)
+ macros_user = m;
+return m;
+}
+
+
/* This function is called when a line that starts with an upper case letter is
encountered. The argument "line" should contain a complete logical line, and
start with the first letter of the macro name. The macro name and the
just skip this definition. It's an error to attempt to redefine a macro without
redef set to TRUE, or to redefine a macro when it hasn't been defined earlier.
It is also an error to define a macro whose name begins with the name of a
-previously defined macro.
+previously defined macro. This is the requirement that make using a tree
+for macros hard; we must check all macros for the substring. Perhaps a
+sorted list, and a bsearch, would work?
Note: it is documented that the other way round works. */
-if ((m = macro_search_prefix(name)))
+for (m = macros; m; m = m->next)
{
- if (m->namelen < namelen) /* substring match */
+ if (Ustrcmp(m->name, name) == 0)
{
- log_write(0, LOG_CONFIG|LOG_PANIC, "\"%s\" cannot be defined as "
- "a macro because previously defined macro \"%s\" is a substring",
- name, m->tnode.name);
- return FALSE;
+ if (!m->command_line && !redef)
+ {
+ log_write(0, LOG_CONFIG|LOG_PANIC, "macro \"%s\" is already "
+ "defined (use \"==\" if you want to redefine it)", name);
+ return FALSE;
+ }
+ break;
}
- /* exact match */
- if (!m->command_line && !redef)
+
+ if (m->namelen < namelen && Ustrstr(name, m->name) != NULL)
{
- log_write(0, LOG_CONFIG|LOG_PANIC, "macro \"%s\" is already "
- "defined (use \"==\" if you want to redefine it", name);
+ log_write(0, LOG_CONFIG|LOG_PANIC, "\"%s\" cannot be defined as "
+ "a macro because previously defined macro \"%s\" is a substring",
+ name, m->name);
return FALSE;
}
- if (m->command_line) /* overriding cmdline definition */
- return TRUE;
+ /* We cannot have this test, because it is documented that a substring
+ macro is permitted (there is even an example).
+ *
+ * if (m->namelen > namelen && Ustrstr(m->name, name) != NULL)
+ * log_write(0, LOG_CONFIG|LOG_PANIC_DIE, "\"%s\" cannot be defined as "
+ * "a macro because it is a substring of previously defined macro \"%s\"",
+ * name, m->name);
+ */
}
+/* Check for an overriding command-line definition. */
+
+if (m && m->command_line) return TRUE;
+
/* Redefinition must refer to an existing macro. */
if (redef)
if (m)
{
m->replen = Ustrlen(s);
- m->tnode.data.ptr = string_copy(s);
+ m->replacement = string_copy(s);
}
else
{
/* Process line for macros. The line is in big_buffer starting at offset len.
Expand big_buffer if needed. Handle definitions of new macros, and
-imacro expansions, rewriting the line in thw buffer.
+macro expansions, rewriting the line in the buffer.
Arguments:
len Offset in buffer of start of line
{
uschar * ss = big_buffer + len;
uschar * s;
+macro_item * m;
/* Find the true start of the physical line - leading spaces are always
ignored. */
if (*s != '=') s = ss; /* Not a macro definition */
}
-/* Scan the line (from after XXX= if present), replacing any macros. Rescan
-after replacement for any later-defined macros. */
+/* Skip leading chars which cannot start a macro name, to avoid multiple
+pointless rescans in Ustrstr calls. */
+
+while (*s && !isupper(*s) && !(*s == '_' && isupper(s[1]))) s++;
+
+/* For each defined macro, scan the line (from after XXX= if present),
+replacing all occurrences of the macro. */
*macro_found = FALSE;
-while (*s)
+if (*s) for (m = *s == '_' ? macros : macros_user; m; m = m->next)
{
- if (isupper(*s) || *s == '_' && isupper(s[1]))
- {
- macro_item * m;
- unsigned mnum = 0;
+ uschar * p, *pp;
+ uschar * t;
- while ((m = macro_search_largest_prefix(s)) && m->m_number > mnum)
- {
- uschar * pp;
- int moveby;
+ while (*s && !isupper(*s) && !(*s == '_' && isupper(s[1]))) s++;
+ if (!*s) break;
- /* Expand the buffer if necessary */
+ t = s;
+ while ((p = Ustrstr(t, m->name)) != NULL)
+ {
+ int moveby;
- while (*newlen - m->namelen + m->replen + 1 > big_buffer_size)
- {
- int newsize = big_buffer_size + BIG_BUFFER_SIZE;
- uschar *newbuffer = store_malloc(newsize);
- memcpy(newbuffer, big_buffer, *newlen + 1);
- s = newbuffer + (s - big_buffer);
- ss = newbuffer + (ss - big_buffer);
- big_buffer_size = newsize;
- store_free(big_buffer);
- big_buffer = newbuffer;
- }
+ READCONF_DEBUG fprintf(stderr, "%s: matched '%s' in '%s'\n", __FUNCTION__, m->name, ss);
+ /* Expand the buffer if necessary */
+
+ while (*newlen - m->namelen + m->replen + 1 > big_buffer_size)
+ {
+ int newsize = big_buffer_size + BIG_BUFFER_SIZE;
+ uschar *newbuffer = store_malloc(newsize);
+ memcpy(newbuffer, big_buffer, *newlen + 1);
+ p = newbuffer + (p - big_buffer);
+ s = newbuffer + (s - big_buffer);
+ ss = newbuffer + (ss - big_buffer);
+ t = newbuffer + (t - big_buffer);
+ big_buffer_size = newsize;
+ store_free(big_buffer);
+ big_buffer = newbuffer;
+ }
- /* Shuffle the remaining characters up or down in the buffer before
- copying in the replacement text. Don't rescan the replacement for this
- same macro. */
+ /* Shuffle the remaining characters up or down in the buffer before
+ copying in the replacement text. Don't rescan the replacement for this
+ same macro. */
- pp = s + m->namelen;
- if ((moveby = m->replen - m->namelen) != 0)
- {
- memmove(s + m->replen, pp, (big_buffer + *newlen) - pp + 1);
- *newlen += moveby;
- }
- Ustrncpy(s, m->tnode.data.ptr, m->replen);
- *macro_found = TRUE;
- mnum = m->m_number;
+ pp = p + m->namelen;
+ if ((moveby = m->replen - m->namelen) != 0)
+ {
+ memmove(p + m->replen, pp, (big_buffer + *newlen) - pp + 1);
+ *newlen += moveby;
}
+ Ustrncpy(p, m->replacement, m->replen);
+ t = p + m->replen;
+ while (*t && !isupper(*t) && !(*t == '_' && isupper(t[1]))) t++;
+ *macro_found = TRUE;
}
- s++;
}
/* An empty macro replacement at the start of a line could mean that ss no
/* Non-admin callers cannot see options that have been flagged secure by the
"hide" prefix. */
-if (!admin_user && ol->type & opt_secure)
+if (!f.admin_user && ol->type & opt_secure)
{
if (no_labels)
printf("%s\n", hidden);
if (Ustrcmp(name, "config") == 0)
{
- print_config(admin_user, no_labels);
+ print_config(f.admin_user, no_labels);
return TRUE;
}
{
/* People store passwords in macros and they were previously not available
for printing. So we have an admin_users restriction. */
- if (!admin_user)
+ if (!f.admin_user)
{
fprintf(stderr, "exim: permission denied\n");
return FALSE;
}
-
- if (name)
- if ((m = macro_search(name)))
- macro_print(m->tnode.name, m->tnode.data.ptr, (void *)(long)names_only);
- else
+ for (m = macros; m; m = m->next)
+ if (!name || Ustrcmp(name, m->name) == 0)
{
- printf("%s %s not found\n", type, name);
- return FALSE;
+ if (names_only)
+ printf("%s\n", CS m->name);
+ else if (no_labels)
+ printf("%s\n", CS m->replacement);
+ else
+ printf("%s=%s\n", CS m->name, CS m->replacement);
+ if (name)
+ return TRUE;
}
- else
- tree_walk(tree_macros, macro_print, (void *)(long)names_only);
+ if (!name) return TRUE;
- return TRUE;
+ printf("%s %s not found\n", type, name);
+ return FALSE;
}
if (names_only)
{
for (; d; d = d->next) printf("%s\n", CS d->name);
- return TRUE;;
+ return TRUE;
}
/* Either search for a given driver, or print all of them */
BOOL rc = FALSE;
if (!name)
printf("\n%s %s:\n", d->name, type);
- else if (Ustrcmp(d->name, name) != 0)
- continue;
+ else if (Ustrcmp(d->name, name) != 0) continue;
for (ol = ol2; ol < ol2 + size; ol++)
if (!(ol->type & opt_hidden))
/* Check the status of the file we have opened, if we have retained root
privileges and the file isn't /dev/null (which *should* be 0666). */
-if (trusted_config && Ustrcmp(filename, US"/dev/null"))
+if (f.trusted_config && Ustrcmp(filename, US"/dev/null"))
{
if (fstat(fileno(config_file), &statbuf) != 0)
log_write(0, LOG_MAIN|LOG_PANIC_DIE, "failed to stat configuration file %s",
readconf_save_config(const uschar *s)
{
save_config_line(string_sprintf("# Exim Configuration (%s)",
- running_in_test_harness ? US"X" : s));
+ f.running_in_test_harness ? US"X" : s));
}
static void