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