Commit f2279f27 f2279f27831f79d036ceab51e093250546f8b9d1 by Sergey Poznyakoff

Convert comsat to mu_cli

1 parent e3840467
......@@ -31,7 +31,7 @@ biff.rc.h: $(top_srcdir)/comsat/biff.rc
$(top_srcdir)/comsat/biff.rc > biff.rc.h
comsatd_LDADD = \
${MU_APP_LIBRARIES}\
${MU_APP_NEW_LIBRARIES}\
${MU_LIB_MBOX}\
${MU_LIB_IMAP}\
${MU_LIB_POP}\
......
......@@ -18,7 +18,7 @@
#include "comsat.h"
#define MU_CFG_COMPATIBILITY /* This source uses deprecated cfg interfaces */
#include "mailutils/libcfg.h"
#include "mailutils/libargp.h"
#include "mailutils/cli.h"
#ifndef PATH_DEV
# define PATH_DEV "/dev"
......@@ -59,44 +59,62 @@ typedef struct utmp UTMP;
#define MAX_TTY_SIZE (sizeof (PATH_TTY_PFX) + sizeof (((UTMP*)0)->ut_line))
const char *program_version = "comsatd (" PACKAGE_STRING ")";
static char doc[] = N_("GNU comsatd -- notify users about incoming mail");
static char args_doc[] = N_("\n--test MBOX-URL MSG-QID");
#define OPT_FOREGROUND 256
int test_mode;
char *biffrc = BIFF_RC;
mu_m_server_t server;
static struct argp_option options[] =
static void
set_inetd_mode (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
{ "test", 't', NULL, 0, N_("run in test mode"), 0 },
{ "foreground", OPT_FOREGROUND, 0, 0, N_("remain in foreground"), 0},
{ "inetd", 'i', 0, 0, N_("run in inetd mode"), 0 },
{ "daemon", 'd', N_("NUMBER"), OPTION_ARG_OPTIONAL,
N_("runs in daemon mode with a maximum of NUMBER children"), 0 },
{ "file", 'f', N_("FILE"), 0,
N_("read FILE instead of .biffrc"), 0 },
{ NULL, 0, NULL, 0, NULL, 0 }
};
mu_m_server_set_mode (server, MODE_INTERACTIVE);
}
static error_t comsatd_parse_opt (int key, char *arg,
struct argp_state *state);
static void
set_daemon_mode (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
mu_m_server_set_mode (server, MODE_DAEMON);
if (arg)
{
size_t max_children;
char *errmsg;
int rc = mu_str_to_c (arg, mu_c_size, &max_children, &errmsg);
if (rc)
{
mu_parseopt_error (po, _("%s: bad argument"), arg);
exit (po->po_exit_error);
}
mu_m_server_set_max_children (server, max_children);
}
}
static struct argp argp = {
options,
comsatd_parse_opt,
args_doc,
doc,
NULL,
NULL, NULL
};
static void
set_foreground (struct mu_parseopt *po, struct mu_option *opt,
char const *arg)
{
mu_m_server_set_foreground (server, 1);
}
static const char *comsat_argp_capa[] = {
"mailutils",
"common",
"debug",
"logging",
"mailbox",
"locking",
NULL
};
static struct mu_option comsat_options[] = {
{ "test", 't', NULL, MU_OPTION_DEFAULT,
N_("run in test mode"),
mu_c_bool, &test_mode },
{ "foreground", 0, NULL, MU_OPTION_DEFAULT,
N_("remain in foreground"),
mu_c_bool, NULL, set_foreground },
{ "inetd", 'i', NULL, MU_OPTION_DEFAULT,
N_("run in inetd mode"),
mu_c_bool, NULL, set_inetd_mode },
{ "daemon", 'd', N_("NUMBER"), MU_OPTION_ARG_OPTIONAL,
N_("runs in daemon mode with a maximum of NUMBER children"),
mu_c_string, NULL, set_daemon_mode },
{ "file", 'f', N_("FILE"), MU_OPTION_DEFAULT,
N_("read FILE instead of .biffrc"),
mu_c_string, &biffrc },
MU_OPTION_END
}, *options[] = { comsat_options, NULL };
#define SUCCESS 0
#define NOT_HERE 1
......@@ -107,7 +125,6 @@ char *hostname;
const char *username;
int require_tty;
int biffrc_errors = BIFFRC_ERRORS_TO_TTY | BIFFRC_ERRORS_TO_ERR;
mu_m_server_t server;
static void comsat_init (void);
static int comsat_main (int fd);
......@@ -118,9 +135,6 @@ static char *mailbox_path (const char *user);
static int change_user (const char *user);
static int reload = 0;
int test_mode;
char *biffrc = BIFF_RC;
static int
biffrc_error_ctl (mu_config_value_t *val, int flag)
{
......@@ -178,48 +192,23 @@ struct mu_cfg_param comsat_cfg_param[] = {
{ NULL }
};
static error_t
comsatd_parse_opt (int key, char *arg, struct argp_state *state)
{
static mu_list_t lst;
switch (key)
{
case 'd':
mu_argp_node_list_new (lst, "mode", "daemon");
if (arg)
mu_argp_node_list_new (lst, "max-children", arg);
break;
case 'f':
biffrc = arg;
break;
case 'i':
mu_argp_node_list_new (lst, "mode", "inetd");
break;
case OPT_FOREGROUND:
mu_argp_node_list_new (lst, "foreground", "yes");
break;
static char const *alt_args[] = { N_("--test MBOX-URL MSG-QID"), NULL };
case 't':
test_mode = 1;
break;
case ARGP_KEY_INIT:
mu_argp_node_list_init (&lst);
break;
case ARGP_KEY_FINI:
mu_argp_node_list_finish (lst, NULL, NULL);
break;
static struct mu_cli_setup cli = {
options,
comsat_cfg_param,
N_("GNU comsatd -- notify users about incoming mail"),
"",
alt_args,
};
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}
static char *capa[] = {
"debug",
"logging",
"mailbox",
"locking",
NULL
};
static RETSIGTYPE
sig_hup (int sig)
......@@ -558,12 +547,11 @@ int
main (int argc, char **argv)
{
int c;
int ind;
char **save_argv;
/* Native Language Support */
MU_APP_INIT_NLS ();
mu_argp_init (NULL, NULL);
comsat_init ();
mu_acl_cfg_init ();
mu_m_server_create (&server, program_version);
......@@ -579,18 +567,15 @@ main (int argc, char **argv)
/* FIXME: timeout is not needed. How to disable it? */
mu_log_syslog = 1;
if (mu_app_init (&argp, comsat_argp_capa, comsat_cfg_param, argc, argv, 0,
&ind, server))
exit (EXIT_FAILURE);
save_argv = argv;
mu_cli (argc, argv, &cli, capa, NULL, &argc, &argv);
if (test_mode)
{
struct passwd *pw;
char *user;
argc -= ind;
argv += ind;
mu_stdstream_strerr_setup (MU_STRERR_STDERR);
biffrc_errors = BIFFRC_ERRORS_TO_ERR;
if (argc < 2 || argc > 2)
......@@ -630,7 +615,7 @@ main (int argc, char **argv)
if (mu_m_server_mode (server) == MODE_DAEMON)
{
if (argv[0][0] != '/')
if (save_argv[0][0] != '/')
mu_diag_output (MU_DIAG_NOTICE,
_("program name is not absolute; reloading will not "
"be possible"));
......@@ -651,7 +636,7 @@ main (int argc, char **argv)
if (reload)
{
mu_diag_output (MU_DIAG_NOTICE, _("restarting"));
execvp (argv[0], argv);
execvp (save_argv[0], save_argv);
}
}
else
......
......@@ -18,6 +18,7 @@
noinst_LTLIBRARIES = libcli.la
libcli_la_SOURCES = \
acl.c\
capa.c\
cli.c\
stdcapa.c
......
/* This file is part of GNU Mailutils
Copyright (C) 2007-2012, 2014-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 "mailutils/acl.h"
#include "mailutils/argcv.h"
#include "mailutils/cidr.h"
#include "mailutils/cfg.h"
#include "mailutils/errno.h"
#include "mailutils/nls.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#define ISSPACE(c) ((c)==' '||(c)=='\t')
#define SKIPWS(p) while (*(p) && ISSPACE (*(p))) (p)++;
static const char *
getword (mu_config_value_t *val, int *pn)
{
int n = (*pn)++;
mu_config_value_t *v;
if (n >= val->v.arg.c)
{
mu_error (_("not enough arguments"));
return NULL;
}
v = &val->v.arg.v[n];
if (mu_cfg_assert_value_type (v, MU_CFG_STRING))
return NULL;
return v->v.string;
}
static int
parsearg (mu_config_value_t *val, struct mu_cidr *cidr, char **prest)
{
const char *w;
int n = 0;
int rc;
if (mu_cfg_assert_value_type (val, MU_CFG_ARRAY))
return 1;
w = getword (val, &n);
if (!w)
return 1;
if (strcmp (w, "from") == 0) {
w = getword (val, &n);
if (!w)
return 1;
}
if (strcmp (w, "any") == 0)
cidr->len = 0;
else
{
rc = mu_cidr_from_string (cidr, w);
if (rc)
{
mu_error (_("invalid source CIDR: %s"), mu_strerror (rc));
return 1;
}
}
if (prest)
{
if (n == val->v.arg.c)
*prest = NULL;
else
{
size_t size = 0;
int i;
char *buf;
for (i = n; i < val->v.arg.c; i++)
{
if (mu_cfg_assert_value_type (&val->v.arg.v[i], MU_CFG_STRING))
return 1;
size += strlen (val->v.arg.v[i].v.string) + 1;
}
buf = malloc (size);
if (!buf)
{
mu_error ("%s", mu_strerror (errno));
return 1;
}
*prest = buf;
for (i = n; i < val->v.arg.c; i++)
{
if (i > n)
*buf++ = ' ';
strcpy (buf, val->v.arg.v[i].v.string);
buf += strlen (buf);
}
*buf = 0;
}
}
else if (n != val->v.arg.c)
{
mu_error (_("junk after IP address"));
return 1;
}
return 0;
}
static int
cb_allow (void *data, mu_config_value_t *val)
{
int rc;
mu_acl_t acl = *(mu_acl_t*)data;
struct mu_cidr cidr;
if (parsearg (val, &cidr, NULL))
return 1;
rc = mu_acl_append (acl, mu_acl_accept, NULL, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
return rc;
}
static int
cb_deny (void *data, mu_config_value_t *val)
{
int rc;
mu_acl_t acl = *(mu_acl_t*)data;
struct mu_cidr cidr;
if (parsearg (val, &cidr, NULL))
return 1;
rc = mu_acl_append (acl, mu_acl_deny, NULL, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
return rc;
}
static int
cb_log (void *data, mu_config_value_t *val)
{
int rc;
mu_acl_t acl = *(mu_acl_t*)data;
struct mu_cidr cidr;
char *rest;
if (parsearg (val, &cidr, &rest))
return 1;
rc = mu_acl_append (acl, mu_acl_log, rest, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
return rc;
}
static int
cb_exec (void *data, mu_config_value_t *val)
{
int rc;
mu_acl_t acl = *(mu_acl_t*)data;
struct mu_cidr cidr;
char *rest;
if (parsearg (val, &cidr, &rest))
return 1;
rc = mu_acl_append (acl, mu_acl_exec, rest, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
return rc;
}
static int
cb_ifexec (void *data, mu_config_value_t *val)
{
int rc;
mu_acl_t acl = *(mu_acl_t*)data;
struct mu_cidr cidr;
char *rest;
if (parsearg (val, &cidr, &rest))
return 1;
rc = mu_acl_append (acl, mu_acl_ifexec, rest, &cidr);
if (rc)
mu_error (_("cannot append acl entry: %s"), mu_strerror (rc));
return rc;
}
static struct mu_cfg_param acl_param[] = {
{ "allow", mu_cfg_callback, NULL, 0, cb_allow,
N_("Allow connections from this IP address. Optional word `from' is "
"allowed between it and its argument. The same holds true for other "
"actions below."),
N_("addr: IP") },
{ "deny", mu_cfg_callback, NULL, 0, cb_deny,
N_("Deny connections from this IP address."),
N_("addr: IP") },
{ "log", mu_cfg_callback, NULL, 0, cb_log,
N_("Log connections from this IP address."),
N_("addr: IP") },
{ "exec", mu_cfg_callback, NULL, 0, cb_exec,
N_("Execute supplied program if a connection from this IP address is "
"requested. Arguments are:\n"
" <addr: IP> <program: string>\n"
"Following macros are expanded in <program> before executing:\n"
" address - Source IP address\n"
" port - Source port number\n") },
{ "ifexec", mu_cfg_callback, NULL, 0, cb_ifexec,
N_("If a connection from this IP address is requested, execute supplied "
"program and allow or deny the connection depending on its exit code. "
"See `exec' for a description of its arguments.") },
{ NULL }
};
static int
acl_section_parser (enum mu_cfg_section_stage stage,
const mu_cfg_node_t *node,
const char *section_label, void **section_data,
void *call_data,
mu_cfg_tree_t *tree)
{
switch (stage)
{
case mu_cfg_section_start:
{
void *data = *section_data;
mu_acl_create ((mu_acl_t*)data);
}
break;
case mu_cfg_section_end:
break;
}
return 0;
}
void
mu_acl_cfg_init (void)
{
struct mu_cfg_section *section;
if (mu_create_canned_section ("acl", &section) == 0)
{
section->parser = acl_section_parser;
mu_cfg_section_add_params (section, acl_param);
}
}