1 /* GNU Mailutils -- a suite of utilities for electronic mail
2 Copyright (C) 2016-2021 Free Software Foundation, Inc.
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 3 of the License, or (at your option) any later version.
8
9 This library 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 GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General
15 Public License along with this library. If not, see
16 <http://www.gnu.org/licenses/>. */
17
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21
22 #include <stdlib.h>
23 #include <inttypes.h>
24 #include <limits.h>
25 #include <string.h>
26 #include <mailutils/cidr.h>
27 #include <mailutils/error.h>
28 #include <mailutils/errno.h>
29 #include <mailutils/util.h>
30 #include <mailutils/alloc.h>
31 #include <mailutils/cctype.h>
32 #include <mailutils/io.h>
33 #include <mailutils/nls.h>
34 #include <mailutils/cstr.h>
35
36 typedef int (*str_to_c_t) (void *tgt, char const *string, char **errmsg);
37
38 static int
to_string(void * tgt,char const * string,char ** errmsg)39 to_string (void *tgt, char const *string, char **errmsg)
40 {
41 char **cptr = tgt;
42 if (string)
43 {
44 *cptr = mu_strdup (string);
45 if (!*cptr)
46 return errno;
47 }
48 else
49 *cptr = NULL;
50 return 0;
51 }
52
53 #define STR_TO_FUN to_short
54 #define STR_TO_TYPE signed short
55 #define STR_TO_MIN SHRT_MIN
56 #define STR_TO_MAX SHRT_MAX
57 #include "to_sn.c"
58
59 #define STR_TO_FUN to_ushort
60 #define STR_TO_TYPE unsigned short
61 #define STR_TO_MAX USHRT_MAX
62 #include "to_un.c"
63
64 #define STR_TO_FUN to_int
65 #define STR_TO_TYPE signed int
66 #define STR_TO_MIN INT_MIN
67 #define STR_TO_MAX INT_MAX
68 #include "to_sn.c"
69
70 #define STR_TO_FUN to_uint
71 #define STR_TO_TYPE unsigned int
72 #define STR_TO_MAX UINT_MAX
73 #include "to_un.c"
74
75 #define STR_TO_FUN to_long
76 #define STR_TO_TYPE signed long
77 #define STR_TO_MIN LONG_MIN
78 #define STR_TO_MAX LONG_MAX
79 #include "to_sn.c"
80
81 #define STR_TO_FUN to_ulong
82 #define STR_TO_TYPE unsigned long
83 #define STR_TO_MAX ULONG_MAX
84 #include "to_un.c"
85
86 #define STR_TO_FUN to_size_t
87 #define STR_TO_TYPE size_t
88 #define STR_TO_MAX ((size_t)-1)
89 #include "to_un.c"
90
91 static int
time_multiplier(const char * str,unsigned * m,unsigned * plen)92 time_multiplier (const char *str, unsigned *m, unsigned *plen)
93 {
94 static struct timetab
95 {
96 char *name;
97 unsigned mul;
98 } tab[] = {
99 { "seconds", 1 },
100 { "minutes", 60 },
101 { "hours", 60*60 },
102 { "days", 24*60*60 },
103 { "weeks", 7*24*60*60 },
104 { "months", 31*7*24*60*60 },
105 { NULL }
106 };
107 struct timetab *p;
108 int slen;
109
110 for (slen = 0; str[slen]; slen++)
111 if (mu_isspace (str[slen]))
112 break;
113
114 for (p = tab; p->name; p++)
115 {
116 if (p->name[0] == mu_tolower (str[0]))
117 {
118 int nlen = strlen (p->name);
119
120 if (nlen > slen)
121 nlen = slen;
122
123 if (strncasecmp (p->name, str, nlen) == 0) {
124 *m = p->mul;
125 if (plen)
126 *plen = nlen;
127 return 0;
128 }
129 }
130 }
131 return 1;
132 }
133
134 static int
to_time_t(void * tgt,char const * string,char ** errmsg)135 to_time_t (void *tgt, char const *string, char **errmsg)
136 {
137 time_t *ptr = tgt;
138 int rc = 0;
139 time_t interval = 0;
140
141 while (*string)
142 {
143 char *p;
144 unsigned long n;
145 unsigned mul, len;
146
147 while (*string && mu_isspace (*string))
148 string++;
149
150 if (!mu_isdigit (*string) && time_multiplier (string, &mul, &len) == 0)
151 {
152 n = 1;
153 string += len;
154 }
155 else
156 {
157 n = strtoul (string, &p, 10);
158 if (*p && !mu_isspace (*p))
159 {
160 string = p;
161 rc = 1;
162 break;
163 }
164
165 while (*p && mu_isspace (*p))
166 p++;
167
168 string = p;
169 if (*string)
170 {
171 if ((rc = time_multiplier (string, &mul, &len)))
172 break;
173 string += len;
174 }
175 else
176 mul = 1;
177 }
178 interval += n * mul;
179 }
180
181 if (rc)
182 {
183 if (errmsg)
184 mu_asprintf (errmsg, _("invalid time specification near %s"), string);
185 return EINVAL;
186 }
187
188 *ptr = interval;
189 return 0;
190 }
191
192 static int
to_bool(void * tgt,char const * string,char ** errmsg)193 to_bool (void *tgt, char const *string, char **errmsg)
194 {
195 int *ptr = tgt;
196
197 if (strcmp (string, "yes") == 0
198 || strcmp (string, "on") == 0
199 || strcmp (string, "t") == 0
200 || strcmp (string, "true") == 0
201 || strcmp (string, "1") == 0)
202 *ptr = 1;
203 else if (strcmp (string, "no") == 0
204 || strcmp (string, "off") == 0
205 || strcmp (string, "nil") == 0
206 || strcmp (string, "false") == 0
207 || strcmp (string, "0") == 0)
208 *ptr = 0;
209 else
210 return EINVAL;
211
212 return 0;
213 }
214
215 #if 0
216 static int
217 to_ipv4 (void *tgt, char const *string, char **errmsg)
218 {
219 struct in_addr *ptr = tgt;
220 struct in_addr addr;
221
222 if (inet_aton (string, &addr) == 0)
223 {
224 mu_diag_at_locus (MU_LOG_ERROR, &mu_cfg_locus, _("not an IPv4"));
225 mu_cfg_error_count++;
226 return 1;
227 }
228 addr.s_addr = ntohl (addr.s_addr);
229
230 *ptr = addr;
231 return 0;
232 }
233 #endif
234
235 static int
to_cidr(void * tgt,char const * string,char ** errmsg)236 to_cidr (void *tgt, char const *string, char **errmsg)
237 {
238 struct mu_cidr *ptr = tgt;
239 return mu_cidr_from_string (ptr, string);
240 }
241
242 static int
to_incr(void * tgt,char const * string,char ** errmsg)243 to_incr (void *tgt, char const *string, char **errmsg)
244 {
245 ++*(int*)tgt;
246 return 0;
247 }
248
249 static int
to_hsize(void * tgt,char const * string,char ** errmsg)250 to_hsize (void *tgt, char const *string, char **errmsg)
251 {
252 return mu_strtosize (string, NULL, tgt);
253 }
254
255 static str_to_c_t str_to_c[] = {
256 [mu_c_string] = to_string,
257 [mu_c_short] = to_short,
258 [mu_c_ushort] = to_ushort,
259 [mu_c_int] = to_int,
260 [mu_c_uint] = to_uint,
261 [mu_c_long] = to_long,
262 [mu_c_ulong] = to_ulong,
263 [mu_c_size] = to_size_t,
264 [mu_c_hsize] = to_hsize,
265 /* FIXME [mu_c_off] = { to_off, generic_dealloc }, */
266 [mu_c_time] = to_time_t,
267 [mu_c_bool] = to_bool,
268 /* FIXME [mu_c_ipv4] = to_ipv4, */
269 [mu_c_cidr] = to_cidr,
270 /* FIXME [mu_c_host] = { to_host, generic_dealloc } */
271 [mu_c_incr] = to_incr,
272 };
273
274 char const *mu_c_type_str[] = {
275 [mu_c_string] = "mu_c_string",
276 [mu_c_short] = "mu_c_short",
277 [mu_c_ushort] = "mu_c_ushort",
278 [mu_c_int] = "mu_c_int",
279 [mu_c_uint] = "mu_c_uint",
280 [mu_c_long] = "mu_c_long",
281 [mu_c_ulong] = "mu_c_ulong",
282 [mu_c_size] = "mu_c_size",
283 [mu_c_hsize] = "mu_c_hsize",
284 [mu_c_off] = "mu_c_off",
285 [mu_c_time] = "mu_c_time",
286 [mu_c_bool] = "mu_c_bool",
287 [mu_c_ipv4] = "mu_c_ipv4",
288 [mu_c_cidr] = "mu_c_cidr",
289 [mu_c_host] = "mu_c_host",
290 [mu_c_incr] = "mu_c_incr",
291 [mu_c_void] = "mu_c_void",
292 };
293
294 int
mu_str_to_c(char const * string,enum mu_c_type type,void * tgt,char ** errmsg)295 mu_str_to_c (char const *string, enum mu_c_type type, void *tgt, char **errmsg)
296 {
297 if (errmsg)
298 *errmsg = NULL;
299 if ((size_t)type >= sizeof (str_to_c) / sizeof (str_to_c[0]))
300 return EINVAL;
301 if (!str_to_c[type])
302 return ENOSYS;
303 return str_to_c[type] (tgt, string, errmsg);
304 }
305