summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--configure.ac1
-rw-r--r--include/mailutils/Makefile.am1
-rw-r--r--include/mailutils/cfg.h5
-rw-r--r--include/mailutils/cli.h55
-rw-r--r--include/mailutils/diag.h4
-rw-r--r--include/mailutils/locker.h2
-rw-r--r--include/mailutils/opt.h16
-rw-r--r--include/mailutils/stdstream.h2
-rw-r--r--libmailutils/Makefile.am3
-rw-r--r--libmailutils/base/locker.c2
-rw-r--r--libmailutils/cfg/driver.c12
-rw-r--r--libmailutils/cfg/lexer.l6
-rw-r--r--libmailutils/cfg/parser.y5
-rw-r--r--libmailutils/cli/Makefile.am26
-rw-r--r--libmailutils/cli/capa.c96
-rw-r--r--libmailutils/cli/cli.c420
-rw-r--r--libmailutils/cli/stdcapa.c466
-rw-r--r--libmailutils/diag/diag.c26
-rw-r--r--libmailutils/opt/help.c8
-rw-r--r--libmailutils/opt/opt.c24
-rw-r--r--libmailutils/opt/progname.c14
-rw-r--r--libmailutils/tests/.gitignore1
-rw-r--r--libmailutils/tests/Makefile.am1
-rw-r--r--libmailutils/tests/parseopt.c4
-rw-r--r--libmailutils/tests/parseopt17.at20
-rw-r--r--libmailutils/tests/parseopt_help05.at2
-rw-r--r--libmailutils/tests/parseopt_help07.at2
-rw-r--r--libmailutils/tests/tcli.c75
-rw-r--r--libmu_sieve/conf.c171
29 files changed, 1390 insertions, 80 deletions
diff --git a/configure.ac b/configure.ac
index dc244dea5..d729747cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1506,6 +1506,7 @@ AC_CONFIG_FILES([
libmailutils/address/Makefile
libmailutils/sockaddr/Makefile
libmailutils/cidr/Makefile
+ libmailutils/cli/Makefile
libmailutils/cfg/Makefile
libmailutils/datetime/Makefile
libmailutils/diag/Makefile
diff --git a/include/mailutils/Makefile.am b/include/mailutils/Makefile.am
index ba87486ce..9ae3929af 100644
--- a/include/mailutils/Makefile.am
+++ b/include/mailutils/Makefile.am
@@ -36,6 +36,7 @@ pkginclude_HEADERS = \
cctype.h\
cfg.h\
cidr.h\
+ cli.h\
cstr.h\
datetime.h\
daemon.h\
diff --git a/include/mailutils/cfg.h b/include/mailutils/cfg.h
index 7ea8e080b..e9f3587ef 100644
--- a/include/mailutils/cfg.h
+++ b/include/mailutils/cfg.h
@@ -79,6 +79,8 @@ struct mu_cfg_parse_hints
char *site_rcfile;
char *custom_rcfile;
char *program;
+ struct mu_cfg_tree *append_tree;
+ void *data;
};
struct mu_cfg_tree
@@ -238,7 +240,8 @@ int mu_config_register_plain_section (const char *parent_path,
#define MU_CFG_FMT_LOCUS 0x080
#define MU_CFG_FMT_VALUE_ONLY 0x100
#define MU_CFG_FMT_PARAM_PATH 0x200
-
+#define MU_PARSE_CONFIG_LINT 0x400
+
#ifdef MU_CFG_COMPATIBILITY
# define MU_CFG_DEPRECATED
#else
diff --git a/include/mailutils/cli.h b/include/mailutils/cli.h
new file mode 100644
index 000000000..2943bc469
--- /dev/null
+++ b/include/mailutils/cli.h
@@ -0,0 +1,55 @@
+/* opt.h -- general-purpose command line option parser
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ GNU Mailutils 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.
+
+ GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef _MAILUTILS_CLI_H
+#define _MAILUTILS_CLI_H
+#include <stdio.h>
+#include <mailutils/types.h>
+#include <mailutils/cfg.h>
+#include <mailutils/opt.h>
+
+typedef void (*mu_cli_capa_commit_fp) (void *);
+
+struct mu_cli_capa
+{
+ char *name;
+ struct mu_option *opt;
+ struct mu_cfg_param *cfg;
+ mu_cfg_section_fp parser;
+ mu_cli_capa_commit_fp commit;
+};
+
+void mu_cli_capa_init (void);
+void mu_cli_capa_register (struct mu_cli_capa *capa);
+void mu_cli_capa_apply (char const *name, mu_list_t opts, mu_list_t commits);
+
+struct mu_cli_setup
+{
+ struct mu_option **optv;
+ struct mu_cfg_param *cfg;
+ char *prog_doc;
+ char *prog_args;
+};
+
+void mu_version_func (struct mu_parseopt *po, FILE *stream);
+void mu_cli (int argc, char **argv, struct mu_cli_setup *setup,
+ char **capa, void *data,
+ int *ret_argc, char ***ret_argv);
+
+char *mu_site_config_file (void);
+
+#endif
diff --git a/include/mailutils/diag.h b/include/mailutils/diag.h
index 3e2bc5188..0a5ebd2de 100644
--- a/include/mailutils/diag.h
+++ b/include/mailutils/diag.h
@@ -29,8 +29,8 @@
extern "C" {
#endif
-extern const char *mu_program_name;
-extern const char *mu_full_program_name;
+extern char *mu_program_name;
+extern char *mu_full_program_name;
#define MU_DIAG_EMERG MU_LOG_EMERG
#define MU_DIAG_ALERT MU_LOG_ALERT
diff --git a/include/mailutils/locker.h b/include/mailutils/locker.h
index b8c4a93c5..718338f72 100644
--- a/include/mailutils/locker.h
+++ b/include/mailutils/locker.h
@@ -103,7 +103,7 @@ extern int mu_locker_set_default_flags (int flags, enum mu_locker_set_mode mode)
extern void mu_locker_set_default_retry_timeout (time_t to);
extern void mu_locker_set_default_retry_count (size_t n);
extern void mu_locker_set_default_expire_timeout (time_t t);
-extern int mu_locker_set_default_external_program (char *path);
+extern int mu_locker_set_default_external_program (char const *path);
/* A flags of 0 means that the default will be used. */
extern int mu_locker_create (mu_locker_t *, const char *filename, int flags);
diff --git a/include/mailutils/opt.h b/include/mailutils/opt.h
index 8e3b03b5d..cc5634211 100644
--- a/include/mailutils/opt.h
+++ b/include/mailutils/opt.h
@@ -23,10 +23,10 @@
#include <mailutils/util.h>
#include <mailutils/cctype.h>
-extern char *mu_progname;
-extern char *mu_absprogname;
+extern char *mu_program_name;
+extern char *mu_full_program_name;
-void mu_set_progname (char const *arg);
+void mu_set_program_name (char const *arg);
#define MU_OPTION_DEFAULT 0
#define MU_OPTION_ARG_OPTIONAL 0x01
@@ -118,7 +118,7 @@ struct mu_parseopt
struct mu_option **po_optv; /* Array of ptrs to option structures */
int po_flags;
- char *po_data; /* Call-specific data */
+ void *po_data; /* Call-specific data */
int po_exit_error; /* Exit on error with this code */
@@ -130,9 +130,10 @@ struct mu_parseopt
char const *po_package_name;
char const *po_package_url;
char const *po_extra_info;
-
- void (*po_help_hook) (FILE *stream); /* FIXME: should take mu_stream_t ?*/
- void (*po_version_hook) (FILE *stream);
+
+ /* FIXME: should these take mu_stream_t ?*/
+ void (*po_help_hook) (struct mu_parseopt *po, FILE *stream);
+ void (*po_version_hook) (struct mu_parseopt *po, FILE *stream);
/* Output data */
int po_ind; /* Index of the next option */
@@ -162,6 +163,7 @@ struct mu_parseopt
int mu_parseopt (struct mu_parseopt *p,
int argc, char **argv, struct mu_option **optv,
int flags);
+void mu_parseopt_error (struct mu_parseopt *po, char const *fmt, ...);
int mu_parseopt_apply (struct mu_parseopt *p);
void mu_parseopt_free (struct mu_parseopt *p);
diff --git a/include/mailutils/stdstream.h b/include/mailutils/stdstream.h
index ac35ff78d..97718811d 100644
--- a/include/mailutils/stdstream.h
+++ b/include/mailutils/stdstream.h
@@ -28,7 +28,7 @@ extern mu_stream_t mu_strin;
extern mu_stream_t mu_strout;
extern mu_stream_t mu_strerr;
-extern const char *mu_program_name;
+extern char *mu_program_name;
#define MU_STRERR_STDERR 0
#define MU_STRERR_SYSLOG 1
diff --git a/libmailutils/Makefile.am b/libmailutils/Makefile.am
index 7a5270c4c..82550c23f 100644
--- a/libmailutils/Makefile.am
+++ b/libmailutils/Makefile.am
@@ -17,7 +17,7 @@
# <http://www.gnu.org/licenses/>.
SUBDIRS = \
- auth base address list sockaddr cidr cfg diag\
+ auth base address list sockaddr cidr cfg cli diag\
filter mailbox mailer mime msgset opt server string stream stdstream\
property url imapio datetime . tests
@@ -33,6 +33,7 @@ libmailutils_la_LIBADD = \
sockaddr/libsockaddr.la\
cidr/libcidr.la\
cfg/libcfg.la\
+ cli/libcli.la\
datetime/libdatetime.la\
diag/libdiag.la\
filter/libfilter.la\
diff --git a/libmailutils/base/locker.c b/libmailutils/base/locker.c
index b4663b948..c4fe993bf 100644
--- a/libmailutils/base/locker.c
+++ b/libmailutils/base/locker.c
@@ -242,7 +242,7 @@ mu_locker_set_default_expire_timeout (time_t t)
}
int
-mu_locker_set_default_external_program (char *path)
+mu_locker_set_default_external_program (char const *path)
{
char *p = strdup (path);
if (!p)
diff --git a/libmailutils/cfg/driver.c b/libmailutils/cfg/driver.c
index c0cd2d5d9..f2a43a367 100644
--- a/libmailutils/cfg/driver.c
+++ b/libmailutils/cfg/driver.c
@@ -463,7 +463,7 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree,
void *target_ptr)
{
int rc = 0;
-
+ struct mu_cfg_cont *cont;
if (!parse_tree)
return 0;
if (hints && (hints->flags & MU_PARSE_CONFIG_DUMP))
@@ -477,13 +477,9 @@ mu_cfg_tree_reduce (mu_cfg_tree_t *parse_tree,
mu_stream_destroy (&stream);
}
- if (root_container)
- {
- struct mu_cfg_cont *cont = mu_build_container (progparam);
- rc = mu_cfg_scan_tree (parse_tree, &cont->v.section, target_ptr,
- NULL);
- mu_config_destroy_container (&cont);
- }
+ cont = mu_build_container (progparam);
+ rc = mu_cfg_scan_tree (parse_tree, &cont->v.section, target_ptr, NULL);
+ mu_config_destroy_container (&cont);
return rc;
}
diff --git a/libmailutils/cfg/lexer.l b/libmailutils/cfg/lexer.l
index 40598a1a2..b6c49ecc1 100644
--- a/libmailutils/cfg/lexer.l
+++ b/libmailutils/cfg/lexer.l
@@ -330,10 +330,16 @@ mu_cfg_parse_file (mu_cfg_tree_t **return_tree, const char *file, int flags)
int rc;
char *full_name = mu_tilde_expansion (file, MU_HIERARCHY_DELIMITER, NULL);
+ if (flags & MU_PARSE_CONFIG_VERBOSE)
+ mu_diag_output (MU_DIAG_INFO, _("opening configuration file %s"),
+ full_name);
if (stat (full_name, &st))
{
if (errno != ENOENT)
mu_error (_("cannot stat `%s': %s"), full_name, mu_strerror (errno));
+ else if (flags & MU_PARSE_CONFIG_VERBOSE)
+ mu_diag_output (MU_DIAG_INFO, _("configuration file %s doesn't exist"),
+ full_name);
free (full_name);
return ENOENT;
}
diff --git a/libmailutils/cfg/parser.y b/libmailutils/cfg/parser.y
index e36b513b0..043f7e0c7 100644
--- a/libmailutils/cfg/parser.y
+++ b/libmailutils/cfg/parser.y
@@ -1589,7 +1589,10 @@ mu_cfg_parse_config (mu_cfg_tree_t **ptree, struct mu_cfg_parse_hints *hints)
mu_cfg_tree_union (&tree, &tmp);
}
}
-
+
+ if (hints->append_tree)
+ mu_cfg_tree_union (&tree, &hints->append_tree);
+
*ptree = tree;
return rc;
}
diff --git a/libmailutils/cli/Makefile.am b/libmailutils/cli/Makefile.am
new file mode 100644
index 000000000..48770e844
--- /dev/null
+++ b/libmailutils/cli/Makefile.am
@@ -0,0 +1,26 @@
+# GNU Mailutils -- a suite of utilities for electronic mail
+# Copyright (C) 2016 Free Software Foundation, Inc.
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# This library 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
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General
+# Public License along with this library. If not, see
+# <http://www.gnu.org/licenses/>.
+
+noinst_LTLIBRARIES = libcli.la
+
+libcli_la_SOURCES = \
+ capa.c\
+ cli.c\
+ stdcapa.c
+
+AM_CPPFLAGS = \
+ @MU_LIB_COMMON_INCLUDES@ -I/libmailutils
diff --git a/libmailutils/cli/capa.c b/libmailutils/cli/capa.c
new file mode 100644
index 000000000..bd5c557e9
--- /dev/null
+++ b/libmailutils/cli/capa.c
@@ -0,0 +1,96 @@
+/* capa.c -- CLI capabilities for GNU Mailutils
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ GNU Mailutils 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.
+
+ GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+#include <mailutils/cli.h>
+#include <mailutils/list.h>
+#include <mailutils/alloc.h>
+#include <mailutils/nls.h>
+
+static mu_list_t capa_list;
+
+static void
+capa_free (void *ptr)
+{
+ struct mu_cli_capa *cp = ptr;
+ free (cp->name);
+ free (cp);
+}
+
+void
+mu_cli_capa_register (struct mu_cli_capa *capa)
+{
+ struct mu_cli_capa *cp = mu_alloc (sizeof (*cp));
+ cp->name = mu_strdup (capa->name);
+ cp->opt = capa->opt;
+ cp->cfg = capa->cfg;
+ cp->parser = capa->parser;
+ cp->commit = capa->commit;
+ if (!capa_list)
+ {
+ mu_list_create (&capa_list);
+ mu_list_set_destroy_item (capa_list, capa_free);
+ }
+ mu_list_append (capa_list, cp);
+}
+
+struct capa_apply
+{
+ char const *name;
+ mu_list_t opts;
+ mu_list_t commits;
+ int found;
+};
+
+static int
+capa_apply (void *item, void *data)
+{
+ struct mu_cli_capa *cp = item;
+ struct capa_apply *ap = data;
+
+ if (strcmp (cp->name, ap->name) == 0)
+ {
+ ap->found = 1;
+ if (cp->opt)
+ mu_list_append (ap->opts, cp->opt);
+ if (cp->commit)
+ mu_list_append (ap->commits, cp->commit);
+ if (cp->parser || cp->cfg)
+ mu_config_root_register_section (NULL, cp->name, NULL,
+ cp->parser, cp->cfg);
+ }
+ return 0;
+}
+
+void
+mu_cli_capa_apply (char const *name, mu_list_t opts, mu_list_t commits)
+{
+ struct capa_apply app;
+ app.name = name;
+ app.opts = opts;
+ app.commits = commits;
+ app.found = 0;
+ mu_list_foreach (capa_list, capa_apply, &app);
+ if (!app.found)
+ mu_error (_("INTERNAL ERROR at %s:%d: unknown standard capability `%s'"),
+ __FILE__, __LINE__, name);
+}
+
+
diff --git a/libmailutils/cli/cli.c b/libmailutils/cli/cli.c
new file mode 100644
index 000000000..2be1af833
--- /dev/null
+++ b/libmailutils/cli/cli.c
@@ -0,0 +1,420 @@
+/* cli.c -- Command line interface for GNU Mailutils
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ GNU Mailutils 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.
+
+ GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+#include <stdlib.h>
+#include <sysexits.h>
+#include <mailutils/cfg.h>
+#include <mailutils/opt.h>
+#include <mailutils/cli.h>
+#include <mailutils/list.h>
+#include <mailutils/alloc.h>
+#include <mailutils/nls.h>
+#include <mailutils/errno.h>
+#include <mailutils/version.h>
+#include <mailutils/stream.h>
+#include <mailutils/stdstream.h>
+#include <mailutils/io.h>
+#include <mailutils/syslog.h>
+
+#ifndef MU_SITE_CONFIG_FILE
+# define MU_SITE_CONFIG_FILE SYSCONFDIR "/mailutils.rc"
+#endif
+
+char *
+mu_site_config_file (void)
+{
+ char *p = getenv ("MU_SITE_CONFIG_FILE");
+ if (p)
+ return p;
+ return MU_SITE_CONFIG_FILE;
+}
+
+
+const char mu_version_copyright[] =
+ /* Do *not* mark this string for translation. %s is a copyright
+ symbol suitable for this locale, and %d is the copyright
+ year. */
+ "Copyright %s 2007-2016 Free Software Foundation, inc.";
+
+void
+mu_version_func (struct mu_parseopt *po, FILE *stream)
+{
+#ifdef GIT_DESCRIBE
+ fprintf (stream, "%s (%s) %s [%s]\n",
+ mu_program_name, PACKAGE_NAME, PACKAGE_VERSION, GIT_DESCRIBE);
+#else
+ fprintf (stream, "%s (%s) %s\n", mu_program_name,
+ PACKAGE_NAME, PACKAGE_VERSION);
+#endif
+ /* TRANSLATORS: Translate "(C)" to the copyright symbol
+ (C-in-a-circle), if this symbol is available in the user's
+ locale. Otherwise, do not translate "(C)"; leave it as-is. */
+ fprintf (stream, mu_version_copyright, _("(C)"));
+ fputs (_("\
+\n\
+License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\nThis is free software: you are free to change and redistribute it.\n\
+There is NO WARRANTY, to the extent permitted by law.\n\
+\n\
+"),
+ stream);
+}
+
+static char gnu_general_help_url[] =
+ N_("General help using GNU software: <http://www.gnu.org/gethelp/>");
+
+
+static void
+change_progname (struct mu_parseopt *po, struct mu_option *opt,
+ char const *arg)
+{
+ po->po_prog_name = mu_strdup (arg);
+}
+
+static void
+no_user_config (struct mu_parseopt *po, struct mu_option *opt,
+ char const *arg)
+{
+ struct mu_cfg_parse_hints *hints = po->po_data;
+ hints->flags &= ~MU_CFG_PARSE_PROGRAM;
+}
+
+static void
+no_site_config (struct mu_parseopt *po, struct mu_option *opt,
+ char const *arg)
+{
+ struct mu_cfg_parse_hints *hints = po->po_data;
+ hints->flags &= ~MU_CFG_PARSE_SITE_RCFILE;
+}
+
+static void
+config_file (struct mu_parseopt *po, struct mu_option *opt,
+ char const *arg)
+{
+ struct mu_cfg_parse_hints *hints = po->po_data;
+ hints->flags |= MU_CFG_PARSE_CUSTOM_RCFILE;
+ hints->custom_rcfile = mu_strdup (arg);
+}
+
+static void
+config_verbose (struct mu_parseopt *po, struct mu_option *opt,
+ char const *arg)
+{
+ struct mu_cfg_parse_hints *hints = po->po_data;
+ if (hints->flags & MU_PARSE_CONFIG_VERBOSE)
+ hints->flags |= MU_PARSE_CONFIG_DUMP;
+ else
+ hints->flags |= MU_PARSE_CONFIG_VERBOSE;
+}
+
+static void
+config_lint (struct mu_parseopt *po, struct mu_option *opt,
+ char const *arg)
+{
+ struct mu_cfg_parse_hints *hints = po->po_data;
+ hints->flags |= MU_PARSE_CONFIG_VERBOSE|MU_PARSE_CONFIG_LINT;
+}
+
+static void
+param_set (struct mu_parseopt *po, struct mu_option *opt, char const *arg)
+{
+ struct mu_cfg_parse_hints *hints = po->po_data;
+ mu_cfg_node_t *node;
+ int rc = mu_cfg_create_subtree (arg, &node);
+ if (rc)
+ mu_parseopt_error (po, "%s: cannot create node: %s",
+ arg, mu_strerror (rc));
+ if (!hints->append_tree)
+ mu_cfg_tree_create (&hints->append_tree);
+ mu_cfg_tree_add_node (hints->append_tree, node);
+}
+
+struct mu_option mu_common_options[] = {
+ MU_OPTION_GROUP(N_("Common options")),
+ { "program-name", 0, N_("NAME"), MU_OPTION_IMMEDIATE|MU_OPTION_HIDDEN,
+ N_("set program name"),
+ mu_c_string, NULL, change_progname },
+
+ { "no-user-config", 0, NULL, MU_OPTION_IMMEDIATE,
+ N_("do not load user configuration file"),
+ mu_c_string, NULL, no_user_config },
+ { "no-user-rcfile", 0, NULL, MU_OPTION_ALIAS },
+
+ { "no-site-config", 0, NULL, MU_OPTION_IMMEDIATE,
+ N_("do not load user configuration file"),
+ mu_c_string, NULL, no_site_config },
+ { "no-site-rcfile", 0, NULL, MU_OPTION_ALIAS },
+
+ { "config-file", 0, N_("FILE"), MU_OPTION_IMMEDIATE,
+ N_("load this configuration file"),
+ mu_c_string, NULL, config_file },
+ { "rcfile", 0, NULL, MU_OPTION_ALIAS },
+
+ { "config-verbose", 0, NULL, MU_OPTION_IMMEDIATE,
+ N_("verbosely log parsing of the configuration files"),
+ mu_c_string, NULL, config_verbose },
+ { "rcfile-verbose", 0, NULL, MU_OPTION_ALIAS },
+
+ { "config-lint", 0, NULL, MU_OPTION_IMMEDIATE,
+ N_("check configuration file syntax and exit"),
+ mu_c_string, NULL, config_lint },
+ { "rcfile-lint", 0, NULL, MU_OPTION_ALIAS },
+
+ { "set", 0, N_("PARAM=VALUE"), MU_OPTION_IMMEDIATE,
+ N_("set configuration parameter"),
+ mu_c_string, NULL, param_set },
+
+ MU_OPTION_END
+};
+
+static void
+show_comp_defaults (struct mu_parseopt *po, struct mu_option *opt,
+ char const *unused)
+{
+ mu_print_options ();
+ exit (0);
+}
+
+static void
+show_config_help (struct mu_parseopt *po, struct mu_option *opt,
+ char const *unused)
+{
+ struct mu_cfg_parse_hints *hints = po->po_data;
+
+ char *comment;
+ mu_stream_t stream;
+ struct mu_cfg_cont *cont;
+ static struct mu_cfg_param dummy_include_param[] = {
+ { "include", mu_c_string, NULL, 0, NULL,
+ N_("Include contents of the given file. If a directory is given, "
+ "include contents of the file <file>/<program>, where "
+ "<program> is the name of the program. This latter form is "
+ "allowed only in the site-wide configuration file."),
+ N_("file-or-directory") },
+ { NULL }
+ };
+
+ mu_stdio_stream_create (&stream, MU_STDOUT_FD, 0);
+
+ mu_asprintf (&comment,
+ "Configuration file structure for %s utility.",
+ po->po_prog_name);
+ mu_cfg_format_docstring (stream, comment, 0);
+ free (comment);
+
+ mu_asprintf (&comment,
+ "For use in global configuration file (%s), enclose it "
+ "in `program %s { ... };",
+ mu_site_config_file (),
+ po->po_prog_name);
+ mu_cfg_format_docstring (stream, comment, 0);
+ free (comment);
+
+ /* FIXME: %s should be replaced by the canonical utility name */
+ mu_asprintf (&comment, "For more information, use `info %s'.",
+ po->po_prog_name);
+ mu_cfg_format_docstring (stream, comment, 0);
+ free (comment);
+
+ cont = mu_config_clone_root_container ();
+ mu_config_container_register_section (&cont, NULL, NULL, NULL, NULL,
+ dummy_include_param, NULL);
+ if (hints->data)
+ mu_config_container_register_section (&cont, NULL, NULL, NULL, NULL,
+ hints->data, NULL);
+ mu_cfg_format_container (stream, cont);
+ mu_config_destroy_container (&cont);
+
+ mu_stream_destroy (&stream);
+ exit (0);
+}
+
+struct mu_option mu_extra_help_options[] = {
+ MU_OPTION_GROUP (N_("Informational options")),
+ { "show-config-options", 0, NULL, MU_OPTION_IMMEDIATE,
+ N_("show compilation options"),
+ mu_c_string, NULL, show_comp_defaults },
+ { "config-help", 0, NULL, MU_OPTION_IMMEDIATE,
+ N_("show configuration file summary"),
+ mu_c_string, NULL, show_config_help },
+ MU_OPTION_END
+};
+
+
+static int
+add_opt_group (void *item, void *data)
+{
+ struct mu_parseopt *po = data;
+ struct mu_option *opt = item;
+ po->po_optv[po->po_optc++] = opt;
+ return 0;
+}
+
+/* Build the list of option groups and configuration sections */
+static struct mu_option **
+init_options (char **capa, struct mu_cli_setup *setup,
+ mu_list_t *ret_comlist)
+{
+ size_t i, s;
+ mu_list_t oplist;
+ struct mu_parseopt po;
+
+ mu_list_create (&oplist);
+ if (setup->optv)
+ {
+ for (i = 0; setup->optv[i]; i++)
+ mu_list_append (oplist, setup->optv[i]);
+ }
+ if (capa)
+ {
+ mu_list_t comlist;
+ mu_list_create (&comlist);
+ for (i = 0; capa[i]; i++)
+ mu_cli_capa_apply (capa[i], oplist, comlist);
+ *ret_comlist = comlist;
+ }
+ else
+ *ret_comlist = NULL;
+
+ mu_list_append (oplist, mu_common_options);
+ mu_list_append (oplist, mu_extra_help_options);
+
+ mu_list_count (oplist, &s);
+
+ po.po_optv = mu_calloc (s + 1, sizeof (po.po_optv[0]));
+ po.po_optc = 0;
+ mu_list_foreach (oplist, add_opt_group, &po);
+ if (po.po_optc != s)
+ abort ();
+ po.po_optv[po.po_optc] = NULL;
+ mu_list_destroy (&oplist);
+ return po.po_optv;
+}
+
+static int
+run_commit (void *item, void *data)
+{
+ mu_cli_capa_commit_fp commit = item;
+ commit (data);
+ return 0;
+}
+
+void
+mu_cli (int argc, char **argv, struct mu_cli_setup *setup, char **capa,
+ void *data,
+ int *ret_argc, char ***ret_argv)
+{
+ struct mu_parseopt po;
+ int flags = 0;
+ struct mu_cfg_tree *parse_tree = NULL;
+ struct mu_cfg_parse_hints hints;
+ struct mu_option **optv;
+ mu_list_t com_list;
+
+ /* Set program name */
+ mu_set_program_name (argv[0]);
+
+ if (!mu_log_tag)
+ mu_log_tag = (char*)mu_program_name;
+
+ /* Initialize standard streams */
+ mu_stdstream_setup (MU_STDSTREAM_RESET_NONE);
+
+ /* Initialize standard capabilities */
+ mu_cli_capa_init ();
+
+ /* Initialize hints */
+ memset (&hints, 0, sizeof (hints));
+ hints.flags |= MU_CFG_PARSE_SITE_RCFILE;
+ hints.site_rcfile = mu_site_config_file ();
+
+ hints.flags |= MU_CFG_PARSE_PROGRAM;
+ hints.program = (char*) mu_program_name;
+
+ hints.data = setup->cfg;
+
+ /* Initialize po */
+ if (setup->prog_doc)
+ {
+ po.po_prog_doc = setup->prog_doc;
+ flags |= MU_PARSEOPT_PROG_DOC;
+ }
+
+ if (setup->prog_args)
+ {
+ po.po_prog_args = setup->prog_args;
+ flags |= MU_PARSEOPT_PROG_ARGS;
+ }
+
+ po.po_package_name = PACKAGE_NAME;
+ flags |= MU_PARSEOPT_PACKAGE_NAME;
+
+ po.po_package_url = PACKAGE_URL;
+ flags |= MU_PARSEOPT_PACKAGE_URL;
+
+ po.po_bug_address = PACKAGE_BUGREPORT;
+ flags |= MU_PARSEOPT_BUG_ADDRESS;
+
+ po.po_extra_info = gnu_general_help_url;
+ flags |= MU_PARSEOPT_EXTRA_INFO;
+
+ po.po_version_hook = mu_version_func;
+ flags |= MU_PARSEOPT_VERSION_HOOK;
+
+ po.po_data = &hints;
+ flags |= MU_PARSEOPT_DATA;
+
+ po.po_exit_error = EX_USAGE;
+
+ optv = init_options (capa, setup, &com_list);
+
+ if (mu_parseopt (&po, argc, argv, optv, flags))
+ exit (EX_USAGE);
+
+ argc -= po.po_arg_start;
+ argv += po.po_arg_start;
+
+ if (ret_argc)
+ {
+ *ret_argc = argc;
+ *ret_argv = argv;
+ }
+ else if (argc)
+ mu_parseopt_error (&po, "%s", _("unexpected arguments"));
+
+ if (mu_cfg_parse_config (&parse_tree, &hints))
+ exit (EX_CONFIG);
+
+ if (mu_cfg_tree_reduce (parse_tree, &hints, setup->cfg, data))
+ exit (EX_CONFIG);
+
+ if (mu_cfg_error_count) //FIXME
+ exit (EX_CONFIG);
+
+ mu_parseopt_apply (&po);
+
+ mu_list_foreach (com_list, run_commit, NULL);
+ mu_list_destroy (&com_list);
+
+ if (hints.flags & MU_PARSE_CONFIG_LINT)
+ exit (0);
+
+ mu_cfg_destroy_tree (&parse_tree);
+ free (optv);
+ mu_parseopt_free (&po);
+}
diff --git a/libmailutils/cli/stdcapa.c b/libmailutils/cli/stdcapa.c
new file mode 100644
index 000000000..3b1cabe54
--- /dev/null
+++ b/libmailutils/cli/stdcapa.c
@@ -0,0 +1,466 @@
+/* stdcapa.c -- Standard CLI capabilities for GNU Mailutils
+ Copyright (C) 2016 Free Software Foundation, Inc.
+
+ GNU Mailutils 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.
+
+ GNU Mailutils 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 GNU Mailutils. If not, see <http://www.gnu.org/licenses/>.
+*/
+#ifdef HAVE_CONFIG_H
+# include <config.