1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2010-2021 Free Software Foundation, Inc.
3
4 GNU Mailutils is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 3, or (at your option)
7 any later version.
8
9 GNU Mailutils is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with GNU Mailutils. If not, see <http://www.gnu.org/licenses/>. */
16
17 #if defined(HAVE_CONFIG_H)
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <string.h>
22 #include <sys/stat.h>
23 #include <mailutils/mailutils.h>
24 #include "mailutils/cli.h"
25 #include <assert.h>
26 #include <glob.h>
27
28 char *mailutilsdir;
29
30 struct mu_tool
31 {
32 char *name;
33 char cmd[1];
34 };
35
36 #define MUTOOL_PREFIX "mailutils-"
37
38 mu_list_t
find_tools(char * pat)39 find_tools (char *pat)
40 {
41 mu_list_t tool_list;
42 char *fpat, *pattern;
43 glob_t gbuf;
44
45 mu_list_create (&tool_list);
46 mu_list_set_destroy_item (tool_list, mu_list_free_item);
47
48 fpat = mu_alloc (sizeof MUTOOL_PREFIX + strlen (pat));
49 strcat (strcpy (fpat, MUTOOL_PREFIX), pat);
50 pattern = mu_make_file_name (mailutilsdir, fpat);
51 free (fpat);
52
53 if (glob (pattern, 0, NULL, &gbuf) == 0)
54 {
55 int i;
56 for (i = 0; i < gbuf.gl_pathc; i++)
57 {
58 char *p;
59 struct mu_tool *tp = mu_alloc (sizeof (*tp) + strlen (gbuf.gl_pathv[i]));
60 strcpy (tp->cmd, gbuf.gl_pathv[i]);
61 p = strrchr (tp->cmd, '/');
62 assert (p != NULL);
63 tp->name = p + sizeof MUTOOL_PREFIX;
64 mu_list_push (tool_list, tp);
65 }
66 globfree (&gbuf);
67 }
68
69 return tool_list;
70 }
71
72 static int
mutool_comp(const void * a,const void * b)73 mutool_comp (const void *a, const void *b)
74 {
75 struct mu_tool const *pa = a;
76 struct mu_tool const *pb = b;
77 return strcmp (pa->name, pb->name);
78 }
79
80 static int
show_help(void * item,void * data)81 show_help (void *item, void *data)
82 {
83 struct mu_tool *t = item;
84 mu_stream_t ostr = data;
85 mu_stream_t istr;
86 char *argv[3];
87 int rc;
88
89 argv[0] = t->cmd;
90 argv[1] = "--describe";
91 argv[2] = NULL;
92 rc = mu_prog_stream_create (&istr, t->cmd,
93 2, argv,
94 0, NULL, MU_STREAM_READ);
95 if (rc == 0)
96 {
97 unsigned margin;
98
99 margin = 2;
100 mu_stream_ioctl (ostr, MU_IOCTL_WORDWRAPSTREAM,
101 MU_IOCTL_WORDWRAP_SET_MARGIN,
102 &margin);
103 mu_stream_printf (ostr, "%s %s", mu_program_name, t->name);
104
105 margin = 29;
106 mu_stream_ioctl (ostr, MU_IOCTL_WORDWRAPSTREAM,
107 MU_IOCTL_WORDWRAP_SET_MARGIN,
108 &margin);
109 rc = mu_stream_copy (ostr, istr, 0, NULL);
110 if (rc)
111 mu_diag_funcall (MU_DIAG_ERR, "mu_stream_copy", t->cmd, rc);
112
113 mu_stream_destroy (&istr);
114 }
115 return 0;
116 }
117
118 void
subcommand_help(mu_stream_t str)119 subcommand_help (mu_stream_t str)
120 {
121 mu_list_t tool_list = find_tools ("*");
122 if (mu_list_is_empty (tool_list))
123 {
124 mu_stream_printf (str, _("No commands found.\n"));
125 }
126 else
127 {
128 mu_list_sort (tool_list, mutool_comp);
129 mu_list_foreach (tool_list, show_help, str);
130 mu_list_destroy (&tool_list);
131 }
132 }
133
134 struct mu_cli_setup cli = {
135 .prog_doc = N_("GNU Mailutils multi-purpose tool."),
136 .prog_args = N_("COMMAND [CMDOPTS]"),
137 .inorder = 1,
138 .prog_doc_hook = subcommand_help
139 };
140
141 struct mu_parseopt pohint = {
142 .po_flags = MU_PARSEOPT_PACKAGE_NAME
143 | MU_PARSEOPT_PACKAGE_URL
144 | MU_PARSEOPT_BUG_ADDRESS
145 | MU_PARSEOPT_EXTRA_INFO
146 | MU_PARSEOPT_VERSION_HOOK,
147 .po_package_name = PACKAGE_NAME,
148 .po_package_url = PACKAGE_URL,
149 .po_bug_address = PACKAGE_BUGREPORT,
150 .po_extra_info = mu_general_help_text,
151 .po_version_hook = mu_version_hook,
152 };
153 struct mu_cfg_parse_hints cfhint = { .flags = 0 };
154
155 int
main(int argc,char ** argv)156 main (int argc, char **argv)
157 {
158 size_t len;
159 mu_list_t tool_list;
160 size_t cnt;
161 struct mu_tool *tp;
162 int rc;
163 char *str;
164
165 #define DEVSFX "/.libs/lt-mailutils"
166 #define DEVSFX_LEN (sizeof (DEVSFX) - 1)
167 #define SUBDIR "libexec"
168 #define SUBDIR_LEN (sizeof (SUBDIR) - 1)
169 len = strlen (argv[0]);
170 if (len > DEVSFX_LEN
171 && strcmp (argv[0] + len - DEVSFX_LEN, DEVSFX) == 0)
172 {
173 len -= DEVSFX_LEN;
174 mailutilsdir = mu_alloc (len + 1 + SUBDIR_LEN + 1);
175 memcpy (mailutilsdir, argv[0], len);
176 mailutilsdir[len++] = '/';
177 strcpy (mailutilsdir + len, SUBDIR);
178 }
179 else
180 mailutilsdir = MAILUTILSDIR;
181
182 /* Native Language Support */
183 MU_APP_INIT_NLS ();
184
185 mu_cli_ext (argc, argv, &cli, &pohint, &cfhint, NULL, NULL, &argc, &argv);
186
187 if (argc < 1)
188 {
189 mu_error (_("what do you want me to do?"));
190 exit (1);
191 }
192
193 if (strcmp (argv[0], "help") == 0)
194 {
195 cli.prog_doc_hook = NULL;
196 cli.prog_doc = N_("display help on mailutils subcommands");
197 cli.prog_args = N_("[COMMAND]");
198 pohint.po_flags |= MU_PARSEOPT_PROG_NAME;
199 mu_asprintf (&str, "%s %s", mu_program_name, argv[0]);
200 pohint.po_prog_name = str;
201
202 mu_cli_ext (argc, argv, &cli, &pohint, &cfhint,
203 NULL, NULL, &argc, &argv);
204
205 if (argc == 0)
206 {
207 mu_stream_t str;
208 unsigned margin;
209
210 if (mu_parseopt_help_stream_create (&str, &pohint, mu_strout))
211 abort ();
212 subcommand_help (str);
213
214 margin = 0;
215 mu_stream_ioctl (str, MU_IOCTL_WORDWRAPSTREAM,
216 MU_IOCTL_WORDWRAP_SET_MARGIN,
217 &margin);
218
219 mu_stream_printf (str, "\n");
220 mu_stream_printf (str,
221 _("Run `%s help COMMAND' to get help on a particular mailutils command."),
222 mu_program_name);
223 mu_stream_destroy (&str);
224 exit (0);
225 }
226 else if (argc == 1)
227 {
228 argv--;
229 argv[0] = argv[1];
230 argv[1] = "--help";
231 argv[2] = NULL;
232 }
233 else
234 {
235 mu_error (_("too many arguments"));
236 exit (1);
237 }
238 }
239
240 tool_list = find_tools (argv[0]);
241 mu_list_count (tool_list, &cnt);
242 if (cnt != 1)
243 {
244 mu_error (_("don't know what %s is"), argv[0]);
245 exit (1);
246 }
247 rc = mu_list_head (tool_list, (void**) &tp);
248 if (rc)
249 {
250 mu_diag_funcall (MU_DIAG_CRIT, "mu_list_head", NULL, rc);
251 exit (2);
252 }
253
254 mu_asprintf (&str, "%s %s", mu_program_name, tp->name);
255 setenv ("MAILUTILS_PROGNAME", str, 1);
256 execv (tp->cmd, argv);
257 mu_diag_funcall (MU_DIAG_CRIT, "execv", tp->cmd, errno);
258 return 2;
259 }
260