1 /* cli.c -- Command line interface for GNU Mailutils
2    Copyright (C) 2016-2021 Free Software Foundation, Inc.
3 
4    GNU Mailutils is free software; you can redistribute it and/or
5    modify it under the terms of the GNU General Public License as
6    published by the Free Software Foundation; either version 3, or (at
7    your option) any later version.
8 
9    GNU Mailutils is distributed in the hope that it will be useful, but
10    WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12    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 #ifdef HAVE_CONFIG_H
18 # include <config.h>
19 #endif
20 #include <stdlib.h>
21 #include <stdarg.h>
22 #include <unistd.h>
23 #include <mailutils/cfg.h>
24 #include <mailutils/opt.h>
25 #include <mailutils/cli.h>
26 #include <mailutils/nls.h>
27 
28 void
mu_cli_simple(int argc,char ** argv,...)29 mu_cli_simple (int argc, char **argv, ...)
30 {
31   struct mu_cli_setup setup;
32   struct mu_parseopt pohint;
33   struct mu_cfg_parse_hints cfhint;
34   char **capa = NULL;
35   void *data = NULL;
36   int *ret_argc = NULL;
37   char ***ret_argv = NULL;
38 
39   mu_opool_t args_pool = NULL, optv_pool = NULL;
40 
41   va_list ap;
42   int opt;
43 
44   memset (&setup, 0, sizeof (setup));
45   memset (&pohint, 0, sizeof (pohint));
46   memset (&cfhint, 0, sizeof (cfhint));
47 
48   va_start (ap, argv);
49   while ((opt = va_arg (ap, int)) != MU_CLI_OPTION_END)
50     {
51       switch (opt)
52 	{
53 	case MU_CLI_OPTION_OPTIONS:
54 	  {
55 	    struct mu_option *p;
56 	    if (!optv_pool)
57 	      mu_opool_create (&optv_pool, MU_OPOOL_ENOMEMABRT);
58 	    p = va_arg (ap, struct mu_option *);
59 	    mu_opool_append (optv_pool, &p, sizeof p);
60 	  }
61 	  break;
62 
63 	case MU_CLI_OPTION_CONFIG:
64 	  setup.cfg = va_arg (ap, struct mu_cfg_param *);
65 	  break;
66 
67 	case MU_CLI_OPTION_CAPABILITIES:
68 	  capa = va_arg (ap, char **);
69 	  break;
70 
71 	case MU_CLI_OPTION_EX_USAGE:
72 	  setup.ex_usage = va_arg (ap, int);
73 	  break;
74 
75 	case MU_CLI_OPTION_EX_CONFIG:
76 	  setup.ex_config = va_arg (ap, int);
77 	  break;
78 
79 	case MU_CLI_OPTION_DATA:
80 	  data = va_arg (ap, void *);
81 	  break;
82 
83 	case MU_CLI_OPTION_IN_ORDER:
84 	  setup.inorder = 1;
85 	  break;
86 
87 	case MU_CLI_OPTION_RETURN_ARGC:
88 	  ret_argc = va_arg (ap, int *);
89 	  break;
90 
91 	case MU_CLI_OPTION_RETURN_ARGV:
92 	  ret_argv = va_arg (ap, char ***);
93 	  break;
94 
95 	case MU_CLI_OPTION_IGNORE_ERRORS:
96 	  pohint.po_flags |= MU_PARSEOPT_IGNORE_ERRORS;
97 	  break;
98 
99 	case MU_CLI_OPTION_NO_STDOPT:
100 	  pohint.po_flags |= MU_PARSEOPT_NO_STDOPT;
101 	  break;
102 
103 	case MU_CLI_OPTION_NO_ERREXIT:
104 	  pohint.po_flags |= MU_PARSEOPT_NO_ERREXIT;
105 	  break;
106 
107 	case MU_CLI_OPTION_IMMEDIATE:
108 	  pohint.po_flags |= MU_PARSEOPT_IMMEDIATE;
109 	  break;
110 
111 	case MU_CLI_OPTION_NO_SORT:
112 	  pohint.po_flags |= MU_PARSEOPT_NO_SORT;
113 	  break;
114 
115 	case MU_CLI_OPTION_SINGLE_DASH:
116 	  pohint.po_flags |= MU_PARSEOPT_SINGLE_DASH;
117 	  break;
118 
119 	case MU_CLI_OPTION_PROG_NAME:
120 	  pohint.po_prog_name = va_arg (ap, char *);
121           if (pohint.po_prog_name)
122 	    pohint.po_flags |= MU_PARSEOPT_PROG_NAME;
123 	  break;
124 
125 	case MU_CLI_OPTION_PROG_DOC:
126 	  pohint.po_prog_doc = va_arg (ap, char *);
127           if (pohint.po_prog_doc)
128 	    pohint.po_flags |= MU_PARSEOPT_PROG_DOC;
129 	  break;
130 
131 	case MU_CLI_OPTION_PROG_ARGS:
132 	  {
133 	    char *p;
134 	    if (!args_pool)
135 	      mu_opool_create (&args_pool, MU_OPOOL_ENOMEMABRT);
136 	    p = va_arg (ap, char *);
137 	    mu_opool_append (args_pool, &p, sizeof p);
138 	  }
139 	  break;
140 
141 	case MU_CLI_OPTION_BUG_ADDRESS:
142 	  pohint.po_bug_address = va_arg (ap, char *);
143           if (pohint.po_bug_address)
144 	    pohint.po_flags |= MU_PARSEOPT_BUG_ADDRESS;
145 	  break;
146 
147 	case MU_CLI_OPTION_PACKAGE_NAME:
148 	  pohint.po_package_name = va_arg (ap, char *);
149           if (pohint.po_package_name)
150 	    pohint.po_flags |= MU_PARSEOPT_PACKAGE_NAME;
151 	  break;
152 
153 	case MU_CLI_OPTION_PACKAGE_URL:
154 	  pohint.po_package_url = va_arg (ap, char *);
155           if (pohint.po_package_url)
156 	    pohint.po_flags |= MU_PARSEOPT_PACKAGE_URL;
157 	  break;
158 
159 	case MU_CLI_OPTION_EXTRA_INFO:
160 	  pohint.po_extra_info = va_arg (ap, char *);
161           if (pohint.po_extra_info)
162 	    pohint.po_flags |= MU_PARSEOPT_EXTRA_INFO;
163 	  break;
164 
165 	case MU_CLI_OPTION_HELP_HOOK:
166 	  pohint.po_help_hook =
167 	    va_arg (ap, void (*) (struct mu_parseopt *, mu_stream_t));
168           if (pohint.po_help_hook)
169 	    pohint.po_flags |= MU_PARSEOPT_HELP_HOOK;
170 	  break;
171 
172 	case MU_CLI_OPTION_VERSION_HOOK:
173 	  pohint.po_version_hook =
174 	    va_arg (ap, void (*) (struct mu_parseopt *, mu_stream_t));
175           if (pohint.po_version_hook)
176 	    pohint.po_flags |= MU_PARSEOPT_VERSION_HOOK;
177 	  break;
178 
179 	case MU_CLI_OPTION_PROG_DOC_HOOK:
180 	  pohint.po_prog_doc_hook =
181 	    va_arg (ap, void (*) (struct mu_parseopt *, mu_stream_t));
182           if (pohint.po_prog_doc_hook)
183 	    pohint.po_flags |= MU_PARSEOPT_PROG_DOC_HOOK;
184 	  break;
185 
186 	case MU_CLI_OPTION_NEGATION:
187 	  pohint.po_negation = va_arg (ap, char *);
188 	  if (pohint.po_negation)
189 	    pohint.po_flags |= MU_PARSEOPT_NEGATION;
190 	  break;
191 
192 	case MU_CLI_OPTION_SPECIAL_ARGS:
193 	  pohint.po_special_args = va_arg (ap, char *);
194           if (pohint.po_special_args)
195 	    pohint.po_flags |= MU_PARSEOPT_SPECIAL_ARGS;
196 	  break;
197 
198 	case MU_CLI_OPTION_CONF_SITE_FILE:
199 	  if ((cfhint.site_file = va_arg (ap, char *)) == NULL)
200 	    cfhint.site_file = mu_site_config_file ();
201 	  cfhint.flags = MU_CFHINT_SITE_FILE;
202 	  break;
203 
204 	case MU_CLI_OPTION_CONF_PER_USER_FILE:
205 	  cfhint.flags |= MU_CFHINT_PER_USER_FILE;
206 	  break;
207 
208 	case MU_CLI_OPTION_CONF_NO_OVERRIDE:
209 	  cfhint.flags |= MU_CFHINT_NO_CONFIG_OVERRIDE;
210 	  break;
211 
212 	case MU_CLI_OPTION_CONF_PROGNAME:
213 	  if ((cfhint.program = va_arg (ap, char *)) != NULL)
214 	    cfhint.flags |= MU_CFHINT_PROGRAM;
215 	  break;
216 
217 	default:
218 	  mu_diag_output (MU_DIAG_CRIT,
219 			  _("%s:%d: INTERNAL ERROR: unrecognized mu_cli_simple option"),
220 			  __FILE__, __LINE__);
221 	  abort ();
222 	}
223     }
224   if (optv_pool)
225     {
226       struct mu_option *p = NULL;
227       mu_opool_append (optv_pool, &p, sizeof p);
228       setup.optv = mu_opool_finish (optv_pool, NULL);
229     }
230   if (args_pool)
231     {
232       char *p = NULL;
233       mu_opool_append (args_pool, &p, sizeof p);
234       pohint.po_prog_args = mu_opool_finish (args_pool, NULL);
235       pohint.po_flags |= MU_PARSEOPT_PROG_ARGS;
236     }
237   mu_cli_ext (argc, argv, &setup, &pohint, &cfhint, capa, data,
238 	      ret_argc, ret_argv);
239   mu_opool_destroy (&args_pool);
240   mu_opool_destroy (&optv_pool);
241   va_end (ap);
242 }
243