/* GNU Mailutils -- a suite of utilities for electronic mail
Copyright (C) 2010-2021 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 . */
#if defined(HAVE_CONFIG_H)
# include
#endif
#include
#include
#include
#include
#include "mailutils/cli.h"
#include
#include
char *mailutilsdir;
struct mu_tool
{
char *name;
char cmd[1];
};
#define MUTOOL_PREFIX "mailutils-"
mu_list_t
find_tools (char *pat)
{
mu_list_t tool_list;
char *fpat, *pattern;
glob_t gbuf;
mu_list_create (&tool_list);
mu_list_set_destroy_item (tool_list, mu_list_free_item);
fpat = mu_alloc (sizeof MUTOOL_PREFIX + strlen (pat));
strcat (strcpy (fpat, MUTOOL_PREFIX), pat);
pattern = mu_make_file_name (mailutilsdir, fpat);
free (fpat);
if (glob (pattern, 0, NULL, &gbuf) == 0)
{
int i;
for (i = 0; i < gbuf.gl_pathc; i++)
{
char *p;
struct mu_tool *tp = mu_alloc (sizeof (*tp) + strlen (gbuf.gl_pathv[i]));
strcpy (tp->cmd, gbuf.gl_pathv[i]);
p = strrchr (tp->cmd, '/');
assert (p != NULL);
tp->name = p + sizeof MUTOOL_PREFIX;
mu_list_push (tool_list, tp);
}
globfree (&gbuf);
}
return tool_list;
}
static int
mutool_comp (const void *a, const void *b)
{
struct mu_tool const *pa = a;
struct mu_tool const *pb = b;
return strcmp (pa->name, pb->name);
}
static int
show_help (void *item, void *data)
{
struct mu_tool *t = item;
mu_stream_t ostr = data;
mu_stream_t istr;
char *argv[3];
int rc;
argv[0] = t->cmd;
argv[1] = "--describe";
argv[2] = NULL;
rc = mu_prog_stream_create (&istr, t->cmd,
2, argv,
0, NULL, MU_STREAM_READ);
if (rc == 0)
{
unsigned margin;
margin = 2;
mu_stream_ioctl (ostr, MU_IOCTL_WORDWRAPSTREAM,
MU_IOCTL_WORDWRAP_SET_MARGIN,
&margin);
mu_stream_printf (ostr, "%s %s", mu_program_name, t->name);
margin = 29;
mu_stream_ioctl (ostr, MU_IOCTL_WORDWRAPSTREAM,
MU_IOCTL_WORDWRAP_SET_MARGIN,
&margin);
rc = mu_stream_copy (ostr, istr, 0, NULL);
if (rc)
mu_diag_funcall (MU_DIAG_ERR, "mu_stream_copy", t->cmd, rc);
mu_stream_destroy (&istr);
}
return 0;
}
void
subcommand_help (mu_stream_t str)
{
mu_list_t tool_list = find_tools ("*");
if (mu_list_is_empty (tool_list))
{
mu_stream_printf (str, _("No commands found.\n"));
}
else
{
mu_list_sort (tool_list, mutool_comp);
mu_list_foreach (tool_list, show_help, str);
mu_list_destroy (&tool_list);
}
}
struct mu_cli_setup cli = {
.prog_doc = N_("GNU Mailutils multi-purpose tool."),
.prog_args = N_("COMMAND [CMDOPTS]"),
.inorder = 1,
.prog_doc_hook = subcommand_help
};
struct mu_parseopt pohint = {
.po_flags = MU_PARSEOPT_PACKAGE_NAME
| MU_PARSEOPT_PACKAGE_URL
| MU_PARSEOPT_BUG_ADDRESS
| MU_PARSEOPT_EXTRA_INFO
| MU_PARSEOPT_VERSION_HOOK,
.po_package_name = PACKAGE_NAME,
.po_package_url = PACKAGE_URL,
.po_bug_address = PACKAGE_BUGREPORT,
.po_extra_info = mu_general_help_text,
.po_version_hook = mu_version_hook,
};
struct mu_cfg_parse_hints cfhint = { .flags = 0 };
int
main (int argc, char **argv)
{
size_t len;
mu_list_t tool_list;
size_t cnt;
struct mu_tool *tp;
int rc;
char *str;
#define DEVSFX "/.libs/lt-mailutils"
#define DEVSFX_LEN (sizeof (DEVSFX) - 1)
#define SUBDIR "libexec"
#define SUBDIR_LEN (sizeof (SUBDIR) - 1)
len = strlen (argv[0]);
if (len > DEVSFX_LEN
&& strcmp (argv[0] + len - DEVSFX_LEN, DEVSFX) == 0)
{
len -= DEVSFX_LEN;
mailutilsdir = mu_alloc (len + 1 + SUBDIR_LEN + 1);
memcpy (mailutilsdir, argv[0], len);
mailutilsdir[len++] = '/';
strcpy (mailutilsdir + len, SUBDIR);
}
else
mailutilsdir = MAILUTILSDIR;
/* Native Language Support */
MU_APP_INIT_NLS ();
mu_cli_ext (argc, argv, &cli, &pohint, &cfhint, NULL, NULL, &argc, &argv);
if (argc < 1)
{
mu_error (_("what do you want me to do?"));
exit (1);
}
if (strcmp (argv[0], "help") == 0)
{
cli.prog_doc_hook = NULL;
cli.prog_doc = N_("display help on mailutils subcommands");
cli.prog_args = N_("[COMMAND]");
pohint.po_flags |= MU_PARSEOPT_PROG_NAME;
mu_asprintf (&str, "%s %s", mu_program_name, argv[0]);
pohint.po_prog_name = str;
mu_cli_ext (argc, argv, &cli, &pohint, &cfhint,
NULL, NULL, &argc, &argv);
if (argc == 0)
{
mu_stream_t str;
unsigned margin;
if (mu_parseopt_help_stream_create (&str, &pohint, mu_strout))
abort ();
subcommand_help (str);
margin = 0;
mu_stream_ioctl (str, MU_IOCTL_WORDWRAPSTREAM,
MU_IOCTL_WORDWRAP_SET_MARGIN,
&margin);
mu_stream_printf (str, "\n");
mu_stream_printf (str,
_("Run `%s help COMMAND' to get help on a particular mailutils command."),
mu_program_name);
mu_stream_destroy (&str);
exit (0);
}
else if (argc == 1)
{
argv--;
argv[0] = argv[1];
argv[1] = "--help";
argv[2] = NULL;
}
else
{
mu_error (_("too many arguments"));
exit (1);
}
}
tool_list = find_tools (argv[0]);
mu_list_count (tool_list, &cnt);
if (cnt != 1)
{
mu_error (_("don't know what %s is"), argv[0]);
exit (1);
}
rc = mu_list_head (tool_list, (void**) &tp);
if (rc)
{
mu_diag_funcall (MU_DIAG_CRIT, "mu_list_head", NULL, rc);
exit (2);
}
mu_asprintf (&str, "%s %s", mu_program_name, tp->name);
setenv ("MAILUTILS_PROGNAME", str, 1);
execv (tp->cmd, argv);
mu_diag_funcall (MU_DIAG_CRIT, "execv", tp->cmd, errno);
return 2;
}