1 /*
2  * Copyright (c) 2007-2014, Anthony Minessale II
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *
12  * * Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in the
14  * documentation and/or other materials provided with the distribution.
15  *
16  * * Neither the name of the original author; nor the names of any contributors
17  * may be used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24  * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER
25  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
27  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
28  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
29  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
30  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *
33  * Contributors:
34  *
35  * Moises Silva <moy@sangoma.com>
36  */
37 
38 #include "private/ftdm_core.h"
39 
40 #ifndef FTDM_MOD_DIR
41 #define FTDM_MOD_DIR "."
42 #endif
43 
44 #define FTDM_MAX_CONF_DIR 512
45 
46 static char g_ftdm_config_dir[FTDM_MAX_CONF_DIR] = FTDM_CONFIG_DIR;
47 static char g_ftdm_mod_dir[FTDM_MAX_CONF_DIR] = FTDM_MOD_DIR;
48 
ftdm_global_set_mod_directory(const char * path)49 FT_DECLARE(void) ftdm_global_set_mod_directory(const char *path)
50 {
51 	snprintf(g_ftdm_mod_dir, sizeof(g_ftdm_mod_dir), "%s", path);
52 	ftdm_log(FTDM_LOG_DEBUG, "New mod directory: %s\n", g_ftdm_mod_dir);
53 }
54 
ftdm_global_set_config_directory(const char * path)55 FT_DECLARE(void) ftdm_global_set_config_directory(const char *path)
56 {
57 	snprintf(g_ftdm_config_dir, sizeof(g_ftdm_config_dir), "%s", path);
58 	ftdm_log(FTDM_LOG_DEBUG, "New config directory: %s\n", g_ftdm_config_dir);
59 }
60 
ftdm_config_open_file(ftdm_config_t * cfg,const char * file_path)61 int ftdm_config_open_file(ftdm_config_t *cfg, const char *file_path)
62 {
63 	FILE *f;
64 	const char *path = NULL;
65 	char path_buf[1024];
66 
67 	if (file_path[0] == '/') {
68 		path = file_path;
69 	} else {
70 		snprintf(path_buf, sizeof(path_buf), "%s%s%s", g_ftdm_config_dir, FTDM_PATH_SEPARATOR, file_path);
71 		path = path_buf;
72 	}
73 
74 	if (!path) {
75 		return 0;
76 	}
77 
78 	memset(cfg, 0, sizeof(*cfg));
79 	cfg->lockto = -1;
80 	ftdm_log(FTDM_LOG_DEBUG, "Configuration file is %s\n", path);
81 	f = fopen(path, "r");
82 
83 	if (!f) {
84 		if (file_path[0] != '/') {
85 			int last = -1;
86 			char *var, *val;
87 
88 			snprintf(path_buf, sizeof(path_buf), "%s%sfreetdm.conf", g_ftdm_config_dir, FTDM_PATH_SEPARATOR);
89 			path = path_buf;
90 
91 			if ((f = fopen(path, "r")) == 0) {
92 				return 0;
93 			}
94 
95 			cfg->file = f;
96 			ftdm_set_string(cfg->path, path);
97 
98 			while (ftdm_config_next_pair(cfg, &var, &val)) {
99 				if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) {
100 					cfg->lockto = cfg->sectno;
101 					return 1;
102 				}
103 			}
104 
105 			ftdm_config_close_file(cfg);
106 			memset(cfg, 0, sizeof(*cfg));
107 			return 0;
108 		}
109 
110 		return 0;
111 	} else {
112 		cfg->file = f;
113 		ftdm_set_string(cfg->path, path);
114 		return 1;
115 	}
116 }
117 
ftdm_config_close_file(ftdm_config_t * cfg)118 void ftdm_config_close_file(ftdm_config_t *cfg)
119 {
120 
121 	if (cfg->file) {
122 		fclose(cfg->file);
123 	}
124 
125 	memset(cfg, 0, sizeof(*cfg));
126 }
127 
128 
129 
ftdm_config_next_pair(ftdm_config_t * cfg,char ** var,char ** val)130 int ftdm_config_next_pair(ftdm_config_t *cfg, char **var, char **val)
131 {
132 	int ret = 0;
133 	char *p, *end;
134 
135 	*var = *val = NULL;
136 
137 	if (!cfg->path) {
138 		return 0;
139 	}
140 
141 	for (;;) {
142 		cfg->lineno++;
143 
144 		if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) {
145 			ret = 0;
146 			break;
147 		}
148 		*var = cfg->buf;
149 
150 		if (**var == '[' && (end = strchr(*var, ']')) != 0) {
151 			*end = '\0';
152 			(*var)++;
153 			if (**var == '+') {
154 				(*var)++;
155 				ftdm_copy_string(cfg->section, *var, sizeof(cfg->section));
156 				cfg->sectno++;
157 
158 				if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) {
159 					break;
160 				}
161 				cfg->catno = 0;
162 				cfg->lineno = 0;
163 				*var = (char *) "";
164 				*val = (char *) "";
165 				return 1;
166 			} else {
167 				ftdm_copy_string(cfg->category, *var, sizeof(cfg->category));
168 				cfg->catno++;
169 			}
170 			continue;
171 		}
172 
173 
174 
175 		if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') {
176 			continue;
177 		}
178 
179 		if (!strncmp(*var, "__END__", 7)) {
180 			break;
181 		}
182 
183 
184 		if ((end = strchr(*var, ';')) && *(end+1) == *end) {
185 			*end = '\0';
186 			end--;
187 		} else if ((end = strchr(*var, '\n')) != 0) {
188 			if (*(end - 1) == '\r') {
189 				end--;
190 			}
191 			*end = '\0';
192 		}
193 
194 		p = *var;
195 		while ((*p == ' ' || *p == '\t') && p != end) {
196 			*p = '\0';
197 			p++;
198 		}
199 		*var = p;
200 
201 
202 		if ((*val = strchr(*var, '=')) == 0) {
203 			ret = -1;
204 			/* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */
205 			continue;
206 		} else {
207 			p = *val - 1;
208 			*(*val) = '\0';
209 			(*val)++;
210 			if (*(*val) == '>') {
211 				*(*val) = '\0';
212 				(*val)++;
213 			}
214 
215 			while ((*p == ' ' || *p == '\t') && p != *var) {
216 				*p = '\0';
217 				p--;
218 			}
219 
220 			p = *val;
221 			while ((*p == ' ' || *p == '\t') && p != end) {
222 				*p = '\0';
223 				p++;
224 			}
225 			*val = p;
226 			ret = 1;
227 			break;
228 		}
229 	}
230 
231 
232 	return ret;
233 
234 }
235 
ftdm_config_get_cas_bits(char * strvalue,unsigned char * outbits)236 FT_DECLARE (int) ftdm_config_get_cas_bits(char *strvalue, unsigned char *outbits)
237 {
238 	char cas_bits[5];
239 	unsigned char bit = 0x8;
240 	int x = 0;
241 	char *double_colon = strchr(strvalue, ':');
242 	if (!double_colon) {
243 		ftdm_log(FTDM_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", strvalue);
244 		return -1;
245 	}
246 	double_colon++;
247 	*outbits = 0;
248 	cas_bits[4] = 0;
249 	if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) {
250 		ftdm_log(FTDM_LOG_ERROR, "Invalid CAS bits specified: '%s', :xxxx definition expected, where x is 1 or 0\n", double_colon);
251 		return -1;
252 	}
253 	ftdm_log(FTDM_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits);
254 	for (; cas_bits[x]; x++) {
255 		if ('1' == cas_bits[x]) {
256 			*outbits |= bit;
257 		} else if ('0' != cas_bits[x]) {
258 			ftdm_log(FTDM_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n",
259 				strvalue);
260 			return -1;
261 		}
262 		bit >>= 1;
263 	}
264 	return 0;
265 }
266 
267 #define PARAMETERS_CHUNK_SIZE 20
ftdm_conf_node_create(const char * name,ftdm_conf_node_t ** node,ftdm_conf_node_t * parent)268 FT_DECLARE(ftdm_status_t) ftdm_conf_node_create(const char *name, ftdm_conf_node_t **node, ftdm_conf_node_t *parent)
269 {
270 	ftdm_conf_node_t *newnode;
271 	ftdm_conf_node_t *sibling = NULL;
272 
273 	ftdm_assert_return(name != NULL, FTDM_FAIL, "null node name");
274 
275 	newnode = ftdm_calloc(1, sizeof(**node));
276 	if (!newnode) {
277 		return FTDM_MEMERR;
278 	}
279 
280 	strncpy(newnode->name, name, sizeof(newnode->name)-1);
281 	newnode->name[sizeof(newnode->name)-1] = 0;
282 
283 	newnode->parameters = ftdm_calloc(PARAMETERS_CHUNK_SIZE, sizeof(*newnode->parameters));
284 	if (!newnode->parameters) {
285 		ftdm_safe_free(newnode);
286 		return FTDM_MEMERR;
287 	}
288 	newnode->t_parameters = PARAMETERS_CHUNK_SIZE;
289 
290 	if (parent) {
291 		/* store who my parent is */
292 		newnode->parent = parent;
293 
294 		/* arrange them in FIFO order (newnode should be last) */
295 		if (!parent->child) {
296 			/* we're the first node being added */
297 			parent->child = newnode;
298 		} else {
299 			if (!parent->last) {
300 				/* we're the second node being added */
301 				parent->last = newnode;
302 				parent->child->next = newnode;
303 				newnode->prev = parent->child;
304 			} else {
305 				/* we're the third or Nth node to be added */
306 				sibling = parent->last;
307 				sibling->next = newnode;
308 				parent->last = newnode;
309 				newnode->prev = sibling;
310 			}
311 		}
312 	}
313 
314 	*node = newnode;
315 
316 	return FTDM_SUCCESS;
317 }
318 
ftdm_conf_node_add_param(ftdm_conf_node_t * node,const char * param,const char * val)319 FT_DECLARE(ftdm_status_t) ftdm_conf_node_add_param(ftdm_conf_node_t *node, const char *param, const char *val)
320 {
321 	void *newparameters;
322 
323 	ftdm_assert_return(param != NULL, FTDM_FAIL, "param is null");
324 	ftdm_assert_return(val != NULL, FTDM_FAIL, "val is null");
325 
326 	if (node->n_parameters == node->t_parameters) {
327 		newparameters = ftdm_realloc(node->parameters, (node->t_parameters + PARAMETERS_CHUNK_SIZE) * sizeof(*node->parameters));
328 		if (!newparameters) {
329 			return FTDM_MEMERR;
330 		}
331 		node->parameters = newparameters;
332 		node->t_parameters = node->n_parameters + PARAMETERS_CHUNK_SIZE;
333 	}
334 	node->parameters[node->n_parameters].var = param;
335 	node->parameters[node->n_parameters].val = val;
336 	node->n_parameters++;
337 	return FTDM_SUCCESS;
338 }
339 
ftdm_conf_node_destroy(ftdm_conf_node_t * node)340 FT_DECLARE(ftdm_status_t) ftdm_conf_node_destroy(ftdm_conf_node_t *node)
341 {
342 	ftdm_conf_node_t *curr = NULL;
343 	ftdm_conf_node_t *child = node->child;
344 	while (child) {
345 		curr = child;
346 		child = curr->next;
347 		ftdm_conf_node_destroy(curr);
348 	}
349 	ftdm_free(node->parameters);
350 	ftdm_free(node);
351 	return FTDM_SUCCESS;
352 }
353 
ftdm_build_dso_path(const char * name,char * path,ftdm_size_t len)354 FT_DECLARE(char *) ftdm_build_dso_path(const char *name, char *path, ftdm_size_t len)
355 {
356 #ifdef WIN32
357     const char *ext = ".dll";
358     //const char *EXT = ".DLL";
359 #elif defined (MACOSX) || defined (DARWIN)
360     const char *ext = ".dylib";
361     //const char *EXT = ".DYLIB";
362 #else
363     const char *ext = ".so";
364     //const char *EXT = ".SO";
365 #endif
366 	if (*name == *FTDM_PATH_SEPARATOR) {
367 		snprintf(path, len, "%s%s", name, ext);
368 	} else {
369 		snprintf(path, len, "%s%s%s%s", g_ftdm_mod_dir, FTDM_PATH_SEPARATOR, name, ext);
370 	}
371 	return path;
372 }
373 
374 /* For Emacs:
375  * Local Variables:
376  * mode:c
377  * indent-tabs-mode:t
378  * tab-width:4
379  * c-basic-offset:4
380  * End:
381  * For VIM:
382  * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
383  */
384