diff options
-rw-r--r-- | configure.ac | 2 | ||||
-rw-r--r-- | lib/Makefile.am | 1 | ||||
-rw-r--r-- | lib/dbcfg.c | 12 | ||||
-rw-r--r-- | lib/libmf.h | 35 | ||||
-rw-r--r-- | lib/optcache.c | 182 | ||||
-rw-r--r-- | lib/utils.c | 48 | ||||
-rw-r--r-- | src/builtin/dns.bi | 6 | ||||
-rw-r--r-- | src/builtin/io.bi | 2 | ||||
-rw-r--r-- | src/builtin/mbox.bi | 2 | ||||
-rw-r--r-- | src/builtin/msg.bi | 2 | ||||
-rw-r--r-- | src/main.c | 723 | ||||
-rw-r--r-- | src/mfdbtool.c | 12 | ||||
-rw-r--r-- | src/savsrv.c | 3 | ||||
-rw-r--r-- | src/srvcfg.c | 456 | ||||
-rw-r--r-- | src/srvcfg.h | 2 |
15 files changed, 559 insertions, 929 deletions
diff --git a/configure.ac b/configure.ac index 8275a927..73713291 100644 --- a/configure.ac +++ b/configure.ac @@ -109,7 +109,7 @@ AH_BOTTOM([ ]) # Check for GNU Mailutils -AM_GNU_MAILUTILS([2.99.99], [all auth dbm sieve cfg argp], [:]) +AM_GNU_MAILUTILS([2.99.991], [all auth dbm sieve], [:]) AC_CHECK_TYPES([struct mu_argp_node_list],,,[#include <mailutils/libargp.h>]) ### Check for Emacs site-lisp directory diff --git a/lib/Makefile.am b/lib/Makefile.am index 4930d4bb..7df87557 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -36,7 +36,6 @@ libmf_a_SOURCES=\ logger.c\ namefixup.c\ nls.c\ - optcache.c\ parsetime.c\ proctitle.c\ server.c\ diff --git a/lib/dbcfg.c b/lib/dbcfg.c index c6682fb6..60a46fd2 100644 --- a/lib/dbcfg.c +++ b/lib/dbcfg.c @@ -84,19 +84,21 @@ struct mu_cfg_param database_section_param[] = { { "file", mu_cfg_callback, NULL, offsetof(struct db_format, dbname), cb_database_file, N_("Name of the database file") }, - { "enable", mu_cfg_bool, NULL, offsetof(struct db_format, enabled), NULL, + { "enable", mu_c_bool, NULL, offsetof(struct db_format, enabled), NULL, N_("Enable or disable the database") }, { "expire-interval", mu_cfg_callback, NULL, offsetof(struct db_format, expire_interval), cb_db_expire_interval, - N_("Set database record expiration interval") }, - + N_("Set database record expiration interval"), + N_("arg: interval") }, { "positive-expire-interval", mu_cfg_callback, NULL, 0, cb_db_positive_expire_interval, - N_("Set positive expiration interval (for database \"cache\" only)") }, + N_("Set positive expiration interval (for database \"cache\" only)"), + N_("arg: interval") }, { "negative-expire-interval", mu_cfg_callback, NULL, 0, cb_db_negative_expire_interval, N_("Set negative expiration interval " - "(for database id \"cache\")") }, + "(for database id \"cache\")"), + N_("arg: interval") }, { NULL } }; diff --git a/lib/libmf.h b/lib/libmf.h index ea7075fd..e27e27c4 100644 --- a/lib/libmf.h +++ b/lib/libmf.h @@ -297,41 +297,6 @@ void mf_server_start(const char *program, const char *dir, const char *pidfile, int flags); -/* optcache.c */ -union mf_option_value { - int ov_bool; - char *ov_string; - time_t ov_time; - size_t ov_size; - mu_list_t ov_list; -}; - -struct mf_option_cache { - char *name; /* option name */ - int (*handler)(char const *opt, union mf_option_value *pval, char const *arg); - /* handler function, which verifies and assigns - arg to pval. */ - void (*set)(union mf_option_value *value); - /* function that actually sets the option */ - union mf_option_value value; /* current value */ - int isset; /* is the value set */ -}; - -#define MF_OCF_NULL 0x01 /* Option_cache array is NULL-terminated */ -#define MF_OCF_STATIC 0x02 /* Option_cache array is static. */ - -void mf_optcache_add(struct mf_option_cache *tab, size_t size, int flags); -int mf_optcache_set_option(char const *name, char const *value); -void mf_optcache_flush(void); -int mf_option_string(char const *opt, union mf_option_value *val, char const *arg); -int mf_option_boolean(char const *opt, union mf_option_value *val, char const *arg); -int mf_option_timeout(char const *opt, union mf_option_value *val, char const *arg); -int mf_option_size(char const *opt, union mf_option_value *val, char const *arg); - - -void mf_init_lock_options(void); - - /* namefixup.c */ void mf_namefixup_register(char **ptr, const char *initval); void mf_file_name_ptr_fixup(char **ptr, char *dir, size_t dirlen); diff --git a/lib/optcache.c b/lib/optcache.c deleted file mode 100644 index 54b10fed..00000000 --- a/lib/optcache.c +++ /dev/null @@ -1,182 +0,0 @@ -/* This file is part of Mailfromd. - Copyright (C) 2005-2011, 2015-2016 Sergey Poznyakoff - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 3, or (at your option) - any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see <http://www.gnu.org/licenses/>. */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <stdlib.h> -#include <errno.h> -#include "libmf.h" -#include "mailutils/alloc.h" - - -struct cache_list_elt { - struct cache_list_elt *next; - struct mf_option_cache *opt; - size_t size; -}; - -static struct cache_list_elt *head, *tail; - -static struct mf_option_cache * -optcache_dup(struct mf_option_cache *tab, size_t size) -{ - struct mf_option_cache *newtab = mu_calloc(size, sizeof(*tab)); - size_t i; - - for (i = 0; i < size; i++) { - newtab[i] = tab[i]; - newtab[i].name = mu_strdup(newtab[i].name); - newtab[i].isset = 0; - } - return newtab; -} - -void -mf_optcache_add(struct mf_option_cache *tab, size_t size, int flags) -{ - struct cache_list_elt *elt; - - elt = mu_alloc(sizeof(*elt)); - elt->next = NULL; - if (tail) - tail->next = elt; - else - head = elt; - tail = elt; - - /* If the array is null-terminated, compute its size */ - if (flags & MF_OCF_NULL) - for (size = 0; tab[size].name; size++) - ; - - /* Unless it is static, make a copy */ - tab = optcache_dup(tab, size); - - elt->opt = tab; - elt->size = size; -} - -static struct mf_option_cache * -find_option(char const *name) -{ - struct cache_list_elt *elt; - - for (elt = head; elt; elt = elt->next) { - size_t i; - struct mf_option_cache *opt; - - for (i = 0, opt = elt->opt; i < elt->size; i++, opt++) { - if (strcmp(opt->name, name) == 0) - return opt; - } - } - return NULL; -} - -int -mf_optcache_set_option(char const *name, char const *value) -{ - int rc; - struct mf_option_cache *p = find_option(name); - if (!p) { - errno = ENOENT; - return 1; - } - rc = p->handler(name, &p->value, value); - if (rc == 0) - p->isset = 1; - return rc; -} - -void -mf_optcache_flush() -{ - struct cache_list_elt *elt; - - for (elt = head; elt; elt = elt->next) { - size_t i; - struct mf_option_cache *opt; - - for (i = 0, opt = elt->opt; i < elt->size; i++, opt++) - if (opt->isset && opt->set) - opt->set(&opt->value); - } -} - - -int -mf_option_string(char const *opt, union mf_option_value *val, char const *arg) -{ - free(val->ov_string); - val->ov_string = strdup(arg); - return 0; -} - -int -mf_option_boolean(char const *opt, union mf_option_value *val, char const *arg) -{ - int b; - - if (strcmp (arg, "yes") == 0 - || strcmp (arg, "true") == 0 - || strcmp (arg, "t") == 0) - b = 1; - else if (strcmp (arg, "no") == 0 - || strcmp (arg, "false") == 0 - || strcmp (arg, "nil") == 0) - b = 0; - else { - char *p; - - b = strtoul(arg, &p, 10); - if (*p) { - errno = EINVAL; - return 1; - } - } - - val->ov_bool = b; - return 0; -} - -int -mf_option_timeout(char const *opt, union mf_option_value *val, char const *arg) -{ - time_t interval; - const char *endp; - - if (parse_time_interval(arg, &interval, &endp)) { - mu_error(_("%s: unrecognized time format (near `%s')"), - opt, endp); - return 1; - } - val->ov_time = interval; - return 0; -} - -int -mf_option_size(char const *opt, union mf_option_value *val, char const *arg) -{ - char *p; - unsigned long n = strtoul(arg, &p, 10); - if (*p) - return 1; - val->ov_size = n; - return 0; -} - diff --git a/lib/utils.c b/lib/utils.c index 2e51ef13..c832ccba 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -125,45 +125,37 @@ config_cb_ignore(void *data, mu_config_value_t *val) int config_cb_lock_retry_count(void *data, mu_config_value_t *val) { + int rc; + char *errmsg; + size_t v; + if (mu_cfg_assert_value_type(val, MU_CFG_STRING)) return 1; - if (mf_optcache_set_option("lock-retry-count", val->v.string)) { - mu_error(_("not a number")); + rc = mu_str_to_c(val->v.string, mu_c_size, &v, &errmsg); + if (rc) { + mu_error(_("%s: not a valid number")); + free(errmsg); return 1; } + mu_locker_set_default_retry_count(v); return 0; } int config_cb_lock_retry_timeout(void *data, mu_config_value_t *val) { - return mf_optcache_set_option("lock-retry-timeout", val->v.string); -} - -static void -set_lock_retry_count(union mf_option_value *val) -{ - mu_locker_set_default_retry_count(val->ov_size); -} - -static void -set_lock_retry_timeout(union mf_option_value *val) -{ - mu_locker_set_default_retry_timeout(val->ov_time); -} - -static struct mf_option_cache lock_option_cache[] = { - { "lock-retry-count", mf_option_size, set_lock_retry_count }, - { "lock-retry-timeout", mf_option_timeout, set_lock_retry_timeout }, - { NULL } -}; - -void -mf_init_lock_options() -{ - mf_optcache_add(lock_option_cache, 0, MF_OCF_NULL|MF_OCF_STATIC); + int rc; + char *errmsg; + time_t v; + + rc = mu_str_to_c(val->v.string, mu_c_time, &v, &errmsg); + if (rc) { + mu_error(_("%s: not a valid interval")); + free(errmsg); + return 1; + } + mu_locker_set_default_retry_timeout(v); } - int stderr_closed_p() diff --git a/src/builtin/dns.bi b/src/builtin/dns.bi index 641cf5ae..d7596f9c 100644 --- a/src/builtin/dns.bi +++ b/src/builtin/dns.bi @@ -25,11 +25,11 @@ static size_t max_ptr = MAX_DNS_PTR; static size_t max_a = MAX_DNS_A; static size_t max_mx = MAX_DNS_MX; static struct mu_cfg_param dns_cfg_param[] = { - { "max-dns-reply-a", mu_cfg_size, &max_a, 0, NULL, + { "max-dns-reply-a", mu_c_size, &max_a, 0, NULL, N_("Maximum number of A records in a DNS reply.") }, - { "max-dns-reply-ptr", mu_cfg_size, &max_a, 0, NULL, + { "max-dns-reply-ptr", mu_c_size, &max_a, 0, NULL, N_("Maximum number of PTR records in a DNS reply.") }, - { "max-dns-reply-mx", mu_cfg_size, &max_mx, 0, NULL, + { "max-dns-reply-mx", mu_c_size, &max_mx, 0, NULL, N_("Maximum number of MX records in a DNS reply.") }, { NULL } }; diff --git a/src/builtin/io.bi b/src/builtin/io.bi index 72ecb770..0875937f 100644 --- a/src/builtin/io.bi +++ b/src/builtin/io.bi @@ -24,7 +24,7 @@ static size_t nstreams = MAX_IOSTREAMS; static struct mu_cfg_param io_cfg_param[] = { - { "max-streams", mu_cfg_size, &nstreams, 0, NULL, + { "max-streams", mu_c_size, &nstreams, 0, NULL, N_("Maximum number of stream descriptors.") }, { NULL } }; diff --git a/src/builtin/mbox.bi b/src/builtin/mbox.bi index f151bd4d..ea4c1f92 100644 --- a/src/builtin/mbox.bi +++ b/src/builtin/mbox.bi @@ -20,7 +20,7 @@ static size_t nmboxes = MAX_MBOXES; static struct mu_cfg_param mbox_cfg_param[] = { - { "max-open-mailboxes", mu_cfg_size, &nmboxes, 0, NULL, + { "max-open-mailboxes", mu_c_size, &nmboxes, 0, NULL, N_("Maximum number of mailboxes to open simultaneously.") }, { NULL } }; diff --git a/src/builtin/msg.bi b/src/builtin/msg.bi index 0de44a20..2fe21363 100644 --- a/src/builtin/msg.bi +++ b/src/builtin/msg.bi @@ -20,7 +20,7 @@ static size_t nmsgs = MAX_MSGS; static struct mu_cfg_param msg_cfg_param[] = { - { "max-open-messages", mu_cfg_size, &nmsgs, 0, NULL, + { "max-open-messages", mu_c_size, &nmsgs, 0, NULL, N_("Maximum number of messages to open simultaneously.") }, { NULL } }; @@ -35,7 +35,7 @@ #include <mailutils/mailutils.h> #include <mailutils/server.h> #include <mailutils/syslog.h> -#include <mailutils/libargp.h> +#include <mailutils/cli.h> #include <mailutils/dbm.h> #include "mailfromd.h" @@ -80,6 +80,10 @@ char *callout_server_url; mu_stream_t mf_strecho; /* Output stream for 'echo' statements */ +#define ARG_UNSET (-1) + +static int trace_option = ARG_UNSET; +static mu_list_t trace_modules; /* Preprocessor helper function */ static void @@ -255,17 +259,8 @@ host_in_relayed_domain_p(char *client) free(hbuf); return rc; } - -static void -set_milter_timeout(union mf_option_value *val) -{ - if (smfi_settimeout(val->ov_time) == MI_FAILURE) { - mu_error(_("invalid milter timeout: %lu"), - (unsigned long)val->ov_time); - exit(EX_USAGE); - } -} +static mu_list_t relayed_domain_files; static int load_relay_file(void *item, void *data) @@ -275,427 +270,389 @@ load_relay_file(void *item, void *data) } static void -set_relay(union mf_option_value *val) +init_relayed_domains(void) { - mu_list_foreach(val->ov_list, load_relay_file, NULL); - mu_list_destroy(&val->ov_list); + mu_list_foreach(relayed_domain_files, load_relay_file, NULL); + mu_list_destroy(relayed_domain_files); } + +/* Command line parsing */ -void -set_stack_trace(union mf_option_value *val) +const char *program_version = "mailfromd (" PACKAGE_STRING ")"; +static char prog_doc[] = N_("mailfromd -- a general purpose milter daemon"); +static char args_doc[] = "[var=value...][SCRIPT]"; + +static void +opt_testmode(struct mu_parseopt *po, struct mu_option *op, char const *arg) { - stack_trace_option = val->ov_bool; + mode = MAILFROMD_TEST; + if (arg) { + test_state = string_to_state(arg); + if (test_state == smtp_state_none) { + mu_parseopt_error(op, + _("unknown smtp state tag: %s"), + arg); + exit(po->po_exit_error); + } + log_stream = "stderr"; + need_script = 1; + } } -static int -option_relay(char const *opt, union mf_option_value *val, char const *newval) +static void +opt_runmode(struct mu_parseopt *po, struct mu_option *op, char const *arg) { - if (!val->ov_list) - mu_list_create(&val->ov_list); - mu_list_append(val->ov_list, strdup(newval)); - return 0; + mode = MAILFROMD_RUN; + if (arg) + main_function_name = arg; + log_stream = "stderr"; + need_script = 1; } -struct mf_option_cache option_cache[] = { - { "stack-trace", mf_option_boolean, set_stack_trace }, - { "milter-timeout", mf_option_timeout, set_milter_timeout }, - { "relay", option_relay, set_relay }, - { NULL } -}; - - -/* Command line parsing */ - -const char *program_version = "mailfromd (" PACKAGE_STRING ")"; -static char doc[] = N_("mailfromd -- a general purpose milter daemon"); -static char args_doc[] = "[var=value...][SCRIPT]"; +static void +opt_lint(struct mu_parseopt *po, struct mu_option *op, char const *arg) +{ + log_stream = "stderr"; + script_check = 1; + need_script = 1; +} -enum mailfromd_option { - OPTION_DAEMON = 256, - OPTION_DOMAIN_FILE, - OPTION_DUMP_CODE, - OPTION_DUMP_GRAMMAR_TRACE, - OPTION_DUMP_LEX_TRACE, - OPTION_DUMP_MACROS, - OPTION_DUMP_TREE, - OPTION_DUMP_XREF, - OPTION_LOCATION_COLUMN, - OPTION_GACOPYZ_LOG, - OPTION_LINT, - OPTION_MILTER_TIMEOUT, - OPTION_MTASIM, - OPTION_NO_PREPROCESSOR, - OPTION_PREPROCESSOR, - OPTION_RUN, - OPTION_SHOW_DEFAULTS, - OPTION_STACK_TRACE, - OPTION_TIMEOUT, - OPTION_TRACE, - OPTION_TRACE_PROGRAM, -}; +static void +opt_show_defaults(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + mode = MAILFROMD_SHOW_DEFAULTS; + need_script = 0; +} -static struct argp_option options[] = { -#define GRP 0 - { NULL, 0, NULL, 0, - N_("Operation modifiers"), GRP }, - { "test", 't', N_("HANDLER"), OPTION_ARG_OPTIONAL, - N_("run in test mode"), GRP+1 }, - { "run", OPTION_RUN, N_("FUNC"), OPTION_ARG_OPTIONAL, - N_("run script and execute function FUNC (\"main\" if not given)"), - GRP+1 }, - { "lint", OPTION_LINT, NULL, 0, - N_("check syntax and exit"), GRP+1 }, - { "syntax-check", 0, NULL, OPTION_ALIAS, NULL, GRP+1 }, - { "show-defaults", OPTION_SHOW_DEFAULTS, NULL, 0, - N_("show compilation defaults"), GRP+1 }, - { "daemon", OPTION_DAEMON, NULL, 0, - N_("run in daemon mode (default)"), GRP+1 }, - - { NULL, 'E', NULL, 0, - N_("preprocess source files and exit"), GRP+1 }, - /* Reserved for future use: */ - { "compile", 'c', NULL, OPTION_HIDDEN, - N_("compile files"), GRP+1 }, - { "load", 'l', N_("FILE"), OPTION_HIDDEN, - N_("load library"), GRP+1 }, - { "load-dir", 'L', N_("DIR"), OPTION_HIDDEN, - N_("add DIR to the load path"), GRP+1 }, - -#undef GRP -#define GRP 20 - { NULL, 0, NULL, 0, - N_("General options"), GRP }, - { "include", 'I', N_("DIR"), 0, - N_("add the directory DIR to the list of directories to be " - "searched for header files"), GRP+1 }, - { "port", 'p', N_("STRING"), 0, - N_("set communication socket"), GRP+1 }, - { "mtasim", OPTION_MTASIM, NULL, 0, - N_("run in mtasim compatibility mode"), GRP+1 }, - { "optimize", 'O', N_("LEVEL"), OPTION_ARG_OPTIONAL, - N_("set code optimization level"), GRP+1 }, - { "variable", 'v', N_("VAR=VALUE"), 0, - N_("assign VALUE to VAR"), GRP+1 }, - { "relayed-domain-file", OPTION_DOMAIN_FILE, N_("FILE"), 0, - N_("read relayed domains from FILE"), GRP+1 }, - -#undef GRP -#define GRP 25 - { NULL, 0, NULL, 0, - N_("Preprocessor options"), GRP }, - { "preprocessor", OPTION_PREPROCESSOR, N_("COMMAND"), 0, - N_("use command as external preprocessor"), GRP+1 }, - { "no-preprocessor", OPTION_NO_PREPROCESSOR, NULL, 0, - N_("disable the use of external preprocessor"), GRP+1 }, - { "define", 'D', N_("NAME[=VALUE]"), 0, - N_("define a preprocessor symbol NAME as having VALUE, or empty"), - GRP+1 }, - { "undefine", 'U', N_("NAME"), 0, - N_("undefine a preprocessor symbol NAME"), - GRP+1 }, - -#undef GRP -#define GRP 30 - { NULL, 0, NULL, 0, - N_("Timeout control"), GRP }, - { "milter-timeout", OPTION_MILTER_TIMEOUT, N_("TIME"), 0, - N_("set MTA connection timeout"), GRP+1 }, - { "timeout", OPTION_TIMEOUT, N_("TIME"), 0, - N_("set I/O operation timeout"), GRP+1 }, - -#undef GRP -#define GRP 40 - { NULL, 0, NULL, 0, - N_("Informational and debugging options"), GRP }, - { "location-column", OPTION_LOCATION_COLUMN, NULL, 0, - N_("print location column numbers in compiler diagnostics messages"), - GRP+1 }, - { "trace", OPTION_TRACE, NULL, 0, - N_("trace executed actions"), GRP+1 }, - { "trace-program", OPTION_TRACE_PROGRAM, N_("MODULES"), - OPTION_ARG_OPTIONAL, - N_("enable filter program tracing"), GRP+1 }, - { "dump-code", OPTION_DUMP_CODE, NULL, 0, - N_("dump disassembled code"), GRP+1 }, - { "dump-grammar-trace", OPTION_DUMP_GRAMMAR_TRACE, NULL, 0, - N_("dump grammar traces"), GRP+1 }, - { "dump-lex-trace", OPTION_DUMP_LEX_TRACE, NULL, 0, - N_("dump lexical analyzer traces"), GRP+1 }, - { "dump-tree", OPTION_DUMP_TREE, NULL, 0, - N_("dump parser tree"), GRP+1 }, - { "dump-macros", OPTION_DUMP_MACROS, NULL, 0, - N_("show used Sendmail macros"), GRP+1 }, - { "xref", OPTION_DUMP_XREF, NULL, 0, - N_("produce a cross-reference listing"), GRP+1 }, - { "dump-xref", 0, NULL, OPTION_ALIAS, NULL, GRP+1 }, - { "gacopyz-log", OPTION_GACOPYZ_LOG, N_("LEVEL"), 0, - N_("set Gacopyz log level"), GRP+1 }, - { "stack-trace", OPTION_STACK_TRACE, NULL, 0, - N_("enable stack traces on runtime errors"), GRP+1 }, -#undef GRP +static void +opt_daemon(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + mode = MAILFROMD_DAEMON; + need_script = 1; +} -#if 0 -/* This entry is to pacify `make check-docs'. The options below - are defined in libmailutils. - */ - { "log-facility", } - { "mailer", } -#endif - { NULL } -}; +static void +opt_include_dir(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + add_include_dir(arg); +} -static int -validate_options() +static void +opt_port(struct mu_parseopt *po, struct mu_option *op, + char const *arg) { - /* FIXME */ - return 0; + mf_srvcfg_add("default", arg); } -struct arguments +static void +opt_mtasim(struct mu_parseopt *po, struct mu_option *op, + char const *arg) { - int trace; - mu_list_t trace_modules; -}; + mtasim_option = 1; + server_flags |= MF_SERVER_FOREGROUND; +} -#define ARG_UNSET (-1) +static void +opt_optimize(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + if (!arg) + optimization_level = 1; + else { + char *p; + optimization_level = strtoul(arg, &p, 0); + if (*p) + mu_parseopt_error(po, + _("-O level must be a non-negative integer")); + } +} static void -init_arguments(struct arguments *args) +opt_variable(struct mu_parseopt *po, struct mu_option *op, + char const *arg) { - args->trace = ARG_UNSET; - args->trace_modules = NULL; + char *p; + struct locus locus = { "<command line>", 1, 0 }; + + p = strchr(arg, '='); + if (!p) { + mu_parseopt_error(po, + _("expected assignment, but found `%s'"), + arg); + exit(po->po_exit_error); + } + *p++ = 0; + defer_initialize_variable(arg, p, &locus); } -static int -flush_trace_module(void *item, void *data) +static void +opt_relayed_domain_file(struct mu_parseopt *po, struct mu_option *op, + char const *arg) { - enable_prog_trace((const char *) item); + if (!relayed_domain_files) + mu_list_create(&relayed_domain_files); + mu_list_append(relayed_domain_files, mu_strdup(arg)); return 0; } static void -flush_arguments(struct arguments *args) +opt_clear_ext_pp(struct mu_parseopt *po, struct mu_option *op, char const *arg) { - if (args->trace != ARG_UNSET) - do_trace = args->trace; - if (args->trace_modules) { - mu_list_foreach(args->trace_modules, flush_trace_module, NULL); - mu_list_destroy(&args->trace_modules); - } + ext_pp = NULL; } static void -destroy_trace_item(void *ptr) +opt_define(struct mu_parseopt *po, struct mu_option *op, char const *arg) { - free(ptr); + ext_pp_options_given = 1; + add_pp_option("-D", arg); } -static error_t -parse_opt(int key, char *arg, struct argp_state *state) +static void +opt_undefine(struct mu_parseopt *po, struct mu_option *op, char const *arg) { - struct arguments *args = state->input; - switch (key) { - case 'D': - ext_pp_options_given = 1; - add_pp_option("-D", arg); - break; + ext_pp_options_given = 1; + add_pp_option("-U", arg); +} - case 'd': - mf_optcache_set_option("debug", arg); - break; - - case 'U': - ext_pp_options_given = 1; - add_pp_option("-U", arg); - break; - - case 'E': - preprocess_option = 1; - break; - - case 'I': - add_include_dir(arg); - break; - - case OPTION_LOCATION_COLUMN: - location_column_option = 1; - break; - - case OPTION_PREPROCESSOR: - ext_pp = arg; - break; +static void +opt_set_milter_timeout(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + int rc; + time_t v; + + if (mu_str_to_c(arg, mu_c_time, &v, NULL)) { + mu_parseopt_error(po, _("%s: not a valid interval"), arg); + exit(po->po_exit_error); + } - case OPTION_NO_PREPROCESSOR: - ext_pp = NULL; - break; - - case 'c': - case 'l': - case 'L': - argp_error(state, - _("the option `-%c' is not yet implemented"), - key); - break; - - case OPTION_LINT: - log_stream = "stderr"; - script_check = 1; - need_script = 1; - break; - - case 'p': - mf_optcache_set_option("port", arg); - break; - - case OPTION_RUN: - mode = MAILFROMD_RUN; - if (arg) - main_function_name = arg; - log_stream = "stderr"; - need_script = 1; - break; - - case 'O': - if (!arg) - optimization_level = 1; - else { - char *p; - optimization_level = strtoul(arg, &p, 0); - if (*p) - argp_error(state, - _("-O level must be a non-negative integer")); - } - break; - - case 't': - mode = MAILFROMD_TEST; - if (arg) { - test_state = string_to_state(arg); - if (test_state == smtp_state_none) - argp_error(state, - _("unknown smtp state tag: %s"), - arg); - } - log_stream = "stderr"; - need_script = 1; - break; + if (smfi_settimeout(v) == MI_FAILURE) { + mu_parseopt_error(po, _("invalid milter timeout: %s"), arg); + exit(po->po_exit_error); + } +} - case 'v': - { - char *p; - struct locus locus = { "<command line>", 1, 0 }; - - p = strchr(arg, '='); - if (!p) - argp_error(state, - _("expected assignment, but found `%s'"), - arg); - *p++ = 0; - defer_initialize_variable(arg, p, &locus); - break; +static void +opt_trace_program(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + if (!trace_modules) { + mu_list_create(&trace_modules); + mu_list_set_destroy_item(trace_modules, destroy_trace_item); } + mu_list_append(trace_modules, mu_strdup(arg ? arg : "all")); +} - case OPTION_DAEMON: - mode = MAILFROMD_DAEMON; - need_script = 1; - break; - - case OPTION_DOMAIN_FILE: - mf_optcache_set_option("relay", arg); - break; +static void +opt_dump_code(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + script_dump_code = 1; + log_stream = "stderr"; +} - case OPTION_DUMP_CODE: - script_dump_code = 1; - log_stream = "stderr"; - break; - - case OPTION_DUMP_GRAMMAR_TRACE: - script_ydebug = 1; - log_stream = "stderr"; - break; - - case OPTION_DUMP_LEX_TRACE: - yy_flex_debug = 1; - log_stream = "stderr"; - break; - - case OPTION_DUMP_MACROS: - script_dump_macros = 1; - log_stream = "stderr"; - break; - - case OPTION_DUMP_TREE: - script_dump_tree = 1; - log_stream = "stderr"; - break; +static void +opt_dump_grammar_trace(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + script_ydebug = 1; + log_stream = "stderr"; +} - case OPTION_DUMP_XREF: - script_dump_xref = 1; - log_stream = "stderr"; - break; - - case OPTION_GACOPYZ_LOG: - { - int lev = gacopyz_string_to_log_level(arg); - if (lev == -1) - argp_error(state, - _("%s: invalid log level"), - arg); - milter_setlogmask(SMI_LOG_FROM(lev)); - break; +static void +opt_dump_lex_trace(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + yy_flex_debug = 1; + log_stream = "stderr"; +} + +static void +opt_dump_macros(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + script_dump_macros = 1; + log_stream = "stderr"; +} + +static void +opt_dump_tree(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + script_dump_tree = 1; + log_stream = "stderr"; +} + +static void +opt_gacopyz_log(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + int lev = gacopyz_string_to_log_level(arg); + if (lev == -1) { + mu_parser_error(po, _("%s: invalid log level"), arg); + exit(po->po_exit_error); } - - case OPTION_MILTER_TIMEOUT: - mf_optcache_set_option("milter-timeout", arg); - break; + milter_setlogmask(SMI_LOG_FROM(lev)); +} - case OPTION_MTASIM: - mtasim_option = 1; - server_flags |= MF_SERVER_FOREGROUND; - break; - - case OPTION_SHOW_DEFAULTS: - mode = MAILFROMD_SHOW_DEFAULTS; - need_script = 0; - break; +static void +opt_dump_xref(struct mu_parseopt *po, struct mu_option *op, + char const *arg) +{ + script_dump_xref = 1; + log_stream = "stderr"; +} - case OPTION_STACK_TRACE: - mf_optcache_set_option("stack-trace", "yes"); - break; +static struct mu_option options[] = { + MU_OPTION_GROUP(N_("Operation modifiers")), + { "test", 't', N_("HANDLER"), MU_OPTION_ARG_OPTIONAL, + N_("run in test mode"), + mu_c_string, NULL, opt_testmode }, + { "run", 0, N_("FUNC"), MU_OPTION_ARG_OPTIONAL, + N_("run script and execute function FUNC (\"main\" if not given)"), + mu_c_string, NULL, opt_runmode }, + { "lint", 0, NULL, MU_OPTION_DEFAULT, + N_("check syntax and exit"), + mu_c_string, NULL, opt_lint }, + { "syntax-check", 0, NULL, MU_OPTION_ALIAS, }, + { "show-defaults", 0, NULL, MU_OPTION_DEFAULT, + N_("show compilation defaults"), + mu_c_string, NULL, opt_show_defaults }, + + { "daemon", 0, NULL, MU_OPTION_DEFAULT, + N_("run in daemon mode (default)"), + mu_c_string, NULL, opt_daemon }, - case OPTION_TIMEOUT: - mf_optcache_set_option("timeout", arg); - break; + { NULL, 'E', NULL, MU_OPTION_DEFAULT, + N_("preprocess source files and exit"), + mu_c_bool, &preprocess_option }, + /* Reserved for future use: */ + { "compile", 'c', NULL, MU_OPTION_HIDDEN, + N_("compile files"), + mu_c_void }, + { "load", 'l', N_("FILE"), MU_OPTION_HIDDEN, + N_("load library"), + mu_c_void }, + { "load-dir", 'L', N_("DIR"), MU_OPTION_HIDDEN, + N_("add DIR to the load path"), + mu_c_void }, + + MU_OPTION_GROUP(N_("General options")), + { "include", 'I', N_("DIR"), MU_OPTION_DEFAULT, + N_("add the directory DIR to the list of directories to be " + "searched for header files"), + mu_c_string, NULL, opt_include_dir }, + { "port", 'p', N_("STRING"), MU_OPTION_DEFAULT, + N_("set communication socket"), + |