]> git.ipfire.org Git - thirdparty/freeswitch.git/blame - src/switch_xml.c
[core] Coverity fixes
[thirdparty/freeswitch.git] / src / switch_xml.c
CommitLineData
a2fcb419 1/*
59241895 2 * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
6e7d5d08 3 * Copyright (C) 2005-2014, Anthony Minessale II <anthm@freeswitch.org>
59241895
MJ
4 *
5 * Version: MPL 1.1
6 *
7 * The contents of this file are subject to the Mozilla Public License Version
8 * 1.1 (the "License"); you may not use this file except in compliance with
9 * the License. You may obtain a copy of the License at
10 * http://www.mozilla.org/MPL/
11 *
12 * Software distributed under the License is distributed on an "AS IS" basis,
13 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
14 * for the specific language governing rights and limitations under the
15 * License.
16 *
17 * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application
18 *
19 * The Initial Developer of the Original Code is
ae220d33 20 * Anthony Minessale II <anthm@freeswitch.org>
59241895
MJ
21 * Portions created by the Initial Developer are Copyright (C)
22 * the Initial Developer. All Rights Reserved.
23 *
24 * Contributor(s):
a2fcb419 25 *
ae220d33 26 * Anthony Minessale II <anthm@freeswitch.org>
59241895 27 * Simon Capper <skyjunky@sbcglobal.net>
4137b360 28 * Marc Olivier Chouinard <mochouinard@moctel.com>
a2fcb419 29 * Raymond Chandler <intralanman@freeswitch.org>
59241895
MJ
30 *
31 * switch_xml.c -- XML PARSER
32 *
33 * Derived from ezxml http://ezxml.sourceforge.net
34 * Original Copyright
35 *
36 * Copyright 2004, 2006 Aaron Voisine <aaron@voisine.org>
37 *
38 * Permission is hereby granted, free of charge, to any person obtaining
39 * a copy of this software and associated documentation files (the
40 * "Software"), to deal in the Software without restriction, including
41 * without limitation the rights to use, copy, modify, merge, publish,
42 * distribute, sublicense, and/or sell copies of the Software, and to
43 * permit persons to whom the Software is furnished to do so, subject to
44 * the following conditions:
45 *
46 * The above copyright notice and this permission notice shall be included
47 * in all copies or substantial portions of the Software.
48 *
49 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
50 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
51 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
52 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
53 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
54 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
55 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
56 */
57
58#include <switch.h>
0629f95c 59#include <switch_stun.h>
59241895 60#ifndef WIN32
dae2cb4a 61#include <sys/wait.h>
59241895
MJ
62#include <switch_private.h>
63#include <glob.h>
64#else /* we're on windoze :( */
65/* glob functions at end of this file */
dd3075a2 66#include <fspr_file_io.h>
59241895
MJ
67
68typedef struct {
886e1ddb
AM
69 size_t gl_pathc; /* Count of total paths so far. */
70 size_t gl_matchc; /* Count of paths matching pattern. */
71 size_t gl_offs; /* Reserved at beginning of gl_pathv. */
72 int gl_flags; /* Copy of flags parameter to glob. */
73 char **gl_pathv; /* List of paths matching pattern. */
59241895 74 /* Copy of errfunc parameter to glob. */
886e1ddb 75 int (*gl_errfunc) (const char *, int);
59241895
MJ
76} glob_t;
77
78/* Believed to have been introduced in 1003.2-1992 */
de13f431
BW
79#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
80#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */
81#define GLOB_ERR 0x0004 /* Return on error. */
82#define GLOB_MARK 0x0008 /* Append / to matching directories. */
59241895 83#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */
de13f431 84#define GLOB_NOSORT 0x0020 /* Don't sort. */
59241895
MJ
85
86/* Error values returned by glob(3) */
87#define GLOB_NOSPACE (-1) /* Malloc call failed. */
88#define GLOB_ABORTED (-2) /* Unignored error. */
89#define GLOB_NOMATCH (-3) /* No match and GLOB_NOCHECK was not set. */
de13f431 90#define GLOB_NOSYS (-4) /* Obsolete: source comptability only. */
59241895
MJ
91
92#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */
93#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
94#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */
de13f431
BW
95#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */
96#define GLOB_LIMIT 0x1000 /* limit number of returned paths */
59241895 97
886e1ddb 98int glob(const char *, int, int (*)(const char *, int), glob_t *);
de13f431 99void globfree(glob_t *);
59241895 100
59241895
MJ
101#endif
102
de13f431 103#define SWITCH_XML_WS "\t\r\n " /* whitespace */
886e1ddb 104#define SWITCH_XML_ERRL 128 /* maximum error string length */
59241895 105
f30e40a8
KR
106static void preprocess_exec_set(char *keyval)
107{
108 char *key = keyval;
0ac27178 109 char *val = strchr(keyval, '=');
f30e40a8
KR
110
111 if (val) {
112 char *ve = val++;
113 while (*val && *val == ' ') {
114 val++;
115 }
116 *ve-- = '\0';
117 while (*ve && *ve == ' ') {
118 *ve-- = '\0';
119 }
120 }
121
122 if (key && val) {
123 switch_stream_handle_t exec_result = { 0 };
124 SWITCH_STANDARD_STREAM(exec_result);
97f42d42 125 if (switch_stream_system(val, &exec_result) == 0) {
f30e40a8
KR
126 if (!zstr(exec_result.data)) {
127 char *tmp = (char *) exec_result.data;
128 tmp = &tmp[strlen(tmp)-1];
129 while (tmp >= (char *) exec_result.data && ( tmp[0] == ' ' || tmp[0] == '\n') ) {
130 tmp[0] = '\0'; /* remove trailing spaces and newlines */
131 tmp--;
132 }
133 switch_core_set_variable(key, exec_result.data);
134 }
135 } else {
136 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error while executing command: %s\n", val);
137 }
138 switch_safe_free(exec_result.data);
139 }
140}
141
0629f95c
AV
142static void preprocess_stun_set(char *keyval)
143{
144 char *key = keyval;
0ac27178 145 char *val = strchr(keyval, '=');
0629f95c
AV
146
147 if (val) {
148 char *ve = val++;
149 while (*val && *val == ' ') {
150 val++;
151 }
152 *ve-- = '\0';
153 while (*ve && *ve == ' ') {
154 *ve-- = '\0';
155 }
156 }
157
158 if (key && val) {
159 char *external_ip = NULL;
160 switch_memory_pool_t *pool;
161
162 switch_core_new_memory_pool(&pool);
163
164 if (switch_stun_ip_lookup(&external_ip, val, pool) == SWITCH_STATUS_SUCCESS) {
165 if (!zstr(external_ip)) {
166 char *tmp = external_ip;
167 tmp = &tmp[strlen(tmp) - 1];
168 while (tmp >= external_ip && (tmp[0] == ' ' || tmp[0] == '\n')) {
169 tmp[0] = '\0'; /* remove trailing spaces and newlines */
170 tmp--;
171 }
172 switch_core_set_variable(key, external_ip);
173 }
174 } else {
175 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "stun-set failed.\n");
176 }
177
178 switch_core_destroy_memory_pool(&pool);
179 }
180}
181
4719d047
SD
182static void preprocess_env_set(char *keyval)
183{
184 char *key = keyval;
0ac27178 185 char *val = strchr(keyval, '=');
4719d047
SD
186
187 if (key && val) {
188 *val++ = '\0';
189
190 if (*val++ == '$') {
191 char *data = getenv(val);
192
193 if (data) {
194 switch_core_set_variable(key, data);
195 }
196 }
197 }
198}
199
c5204c21 200static int preprocess(const char *cwd, const char *file, FILE *write_fd, int rlevel);
59241895
MJ
201
202typedef struct switch_xml_root *switch_xml_root_t;
de13f431
BW
203struct switch_xml_root { /* additional data for the root tag */
204 struct switch_xml xml; /* is a super-struct built on top of switch_xml struct */
205 switch_xml_t cur; /* current xml tree insertion point */
206 char *m; /* original xml string */
34bd0e5e 207 switch_size_t len; /* length of allocated memory */
bc46c9a0 208 uint8_t dynamic; /* Free the original string when calling switch_xml_free */
de13f431
BW
209 char *u; /* UTF-8 conversion of string if original was UTF-16 */
210 char *s; /* start of work area */
211 char *e; /* end of work area */
212 char **ent; /* general entities (ampersand sequences) */
213 char ***attr; /* default attributes */
214 char ***pi; /* processing instructions */
215 short standalone; /* non-zero if <?xml standalone="yes"?> */
216 char err[SWITCH_XML_ERRL]; /* error string */
59241895
MJ
217};
218
de13f431 219char *SWITCH_XML_NIL[] = { NULL }; /* empty, null terminated array of strings */
59241895
MJ
220
221struct switch_xml_binding {
222 switch_xml_search_function_t function;
223 switch_xml_section_t sections;
224 void *user_data;
225 struct switch_xml_binding *next;
226};
227
228
229static switch_xml_binding_t *BINDINGS = NULL;
230static switch_xml_t MAIN_XML_ROOT = NULL;
c5831538 231static switch_memory_pool_t *XML_MEMORY_POOL = NULL;
4714ed43 232
c5831538 233static switch_thread_rwlock_t *B_RWLOCK = NULL;
4714ed43 234static switch_mutex_t *XML_LOCK = NULL;
2582bbcb 235static switch_mutex_t *CACHE_MUTEX = NULL;
4714ed43 236static switch_mutex_t *REFLOCK = NULL;
3ed59f1d 237static switch_mutex_t *FILE_LOCK = NULL;
4714ed43 238
3aaa6209 239SWITCH_DECLARE_NONSTD(switch_xml_t) __switch_xml_open_root(uint8_t reload, const char **err, void *user_data);
07a71592
AM
240
241static switch_xml_open_root_function_t XML_OPEN_ROOT_FUNCTION = (switch_xml_open_root_function_t)__switch_xml_open_root;
242static void *XML_OPEN_ROOT_FUNCTION_USER_DATA = NULL;
243
2582bbcb 244static switch_hash_t *CACHE_HASH = NULL;
a2fcb419 245static switch_hash_t *CACHE_EXPIRES_HASH = NULL;
59241895
MJ
246
247struct xml_section_t {
248 const char *name;
de13f431 249 /* switch_xml_section_t section; */
59241895
MJ
250 uint32_t section;
251};
252
253static struct xml_section_t SECTIONS[] = {
254 {"result", SWITCH_XML_SECTION_RESULT},
255 {"config", SWITCH_XML_SECTION_CONFIG},
256 {"directory", SWITCH_XML_SECTION_DIRECTORY},
257 {"dialplan", SWITCH_XML_SECTION_DIALPLAN},
5b8a1337 258 {"languages", SWITCH_XML_SECTION_LANGUAGES},
7333d46d 259 {"chatplan", SWITCH_XML_SECTION_CHATPLAN},
4dc7b3b2 260 {"channels", SWITCH_XML_SECTION_CHANNELS},
59241895
MJ
261 {NULL, 0}
262};
263
264SWITCH_DECLARE(switch_xml_section_t) switch_xml_parse_section_string(const char *str)
265{
266 size_t x;
267 char buf[1024] = "";
de13f431 268 /*switch_xml_section_t sections = SWITCH_XML_SECTION_RESULT; */
59241895 269 uint32_t sections = SWITCH_XML_SECTION_RESULT;
886e1ddb 270
59241895
MJ
271 if (str) {
272 for (x = 0; x < strlen(str); x++) {
273 buf[x] = (char) tolower((int) str[x]);
274 }
275 for (x = 0;; x++) {
276 if (!SECTIONS[x].name) {
277 break;
278 }
279 if (strstr(buf, SECTIONS[x].name)) {
280 sections |= SECTIONS[x].section;
281 }
282 }
283 }
284 return (switch_xml_section_t) sections;
285}
286
287SWITCH_DECLARE(switch_status_t) switch_xml_unbind_search_function(switch_xml_binding_t **binding)
288{
289 switch_xml_binding_t *ptr, *last = NULL;
290 switch_status_t status = SWITCH_STATUS_FALSE;
291
8ec9b8f7
AM
292
293 switch_thread_rwlock_wrlock(B_RWLOCK);
59241895
MJ
294 for (ptr = BINDINGS; ptr; ptr = ptr->next) {
295 if (ptr == *binding) {
296 if (last) {
297 last->next = (*binding)->next;
298 } else {
299 BINDINGS = (*binding)->next;
300 }
301 status = SWITCH_STATUS_SUCCESS;
302 break;
303 }
304 last = ptr;
305 }
8ec9b8f7 306 switch_thread_rwlock_unlock(B_RWLOCK);
59241895
MJ
307
308 return status;
309}
310
311SWITCH_DECLARE(switch_status_t) switch_xml_unbind_search_function_ptr(switch_xml_search_function_t function)
312{
313 switch_xml_binding_t *ptr, *last = NULL;
314 switch_status_t status = SWITCH_STATUS_FALSE;
315
8ec9b8f7 316 switch_thread_rwlock_wrlock(B_RWLOCK);
59241895
MJ
317 for (ptr = BINDINGS; ptr; ptr = ptr->next) {
318 if (ptr->function == function) {
30a13ca0
AM
319 status = SWITCH_STATUS_SUCCESS;
320
59241895
MJ
321 if (last) {
322 last->next = ptr->next;
323 } else {
324 BINDINGS = ptr->next;
30a13ca0
AM
325 last = NULL;
326 continue;
59241895 327 }
59241895
MJ
328 }
329 last = ptr;
330 }
8ec9b8f7 331 switch_thread_rwlock_unlock(B_RWLOCK);
59241895
MJ
332
333 return status;
334}
335
fc6a7ced
AM
336SWITCH_DECLARE(void) switch_xml_set_binding_sections(switch_xml_binding_t *binding, switch_xml_section_t sections)
337{
338 switch_assert(binding);
339 binding->sections = sections;
340}
341
342SWITCH_DECLARE(void) switch_xml_set_binding_user_data(switch_xml_binding_t *binding, void *user_data)
343{
344 switch_assert(binding);
345 binding->user_data = user_data;
346}
347
34931616
AM
348SWITCH_DECLARE(switch_xml_section_t) switch_xml_get_binding_sections(switch_xml_binding_t *binding)
349{
350 return binding->sections;
351}
352
353SWITCH_DECLARE(void *) switch_xml_get_binding_user_data(switch_xml_binding_t *binding)
354{
355 return binding->user_data;
356}
357
de13f431 358SWITCH_DECLARE(switch_status_t) switch_xml_bind_search_function_ret(switch_xml_search_function_t function,
886e1ddb 359 switch_xml_section_t sections, void *user_data, switch_xml_binding_t **ret_binding)
59241895
MJ
360{
361 switch_xml_binding_t *binding = NULL, *ptr = NULL;
362 assert(function != NULL);
363
364 if (!(binding = (switch_xml_binding_t *) switch_core_alloc(XML_MEMORY_POOL, sizeof(*binding)))) {
365 return SWITCH_STATUS_MEMERR;
366 }
367
368 binding->function = function;
369 binding->sections = sections;
370 binding->user_data = user_data;
371
8ec9b8f7 372 switch_thread_rwlock_wrlock(B_RWLOCK);
59241895
MJ
373 for (ptr = BINDINGS; ptr && ptr->next; ptr = ptr->next);
374
375 if (ptr) {
376 ptr->next = binding;
377 } else {
378 BINDINGS = binding;
379 }
446d7285 380
ff0c6deb
AM
381 if (ret_binding) {
382 *ret_binding = binding;
446d7285
AM
383 }
384
8ec9b8f7 385 switch_thread_rwlock_unlock(B_RWLOCK);
59241895
MJ
386
387 return SWITCH_STATUS_SUCCESS;
388}
389
390SWITCH_DECLARE(switch_xml_t) switch_xml_find_child(switch_xml_t node, const char *childname, const char *attrname, const char *value)
391{
392 switch_xml_t p = NULL;
393
394 if (!(childname && attrname && value)) {
395 return node;
396 }
397
398 for (p = switch_xml_child(node, childname); p; p = p->next) {
399 const char *aname = switch_xml_attr(p, attrname);
0ac27178 400 if (aname && !strcasecmp(aname, value)) {
59241895
MJ
401 break;
402 }
403 }
404
405 return p;
406}
407
886e1ddb 408SWITCH_DECLARE(switch_xml_t) switch_xml_find_child_multi(switch_xml_t node, const char *childname,...)
ed100f44
AM
409{
410 switch_xml_t p = NULL;
886e1ddb
AM
411 const char *names[256] = { 0 };
412 const char *vals[256] = { 0 };
ed100f44
AM
413 int x, i = 0;
414 va_list ap;
376b42c3 415 const char *attrname, *value = NULL;
ed100f44
AM
416
417 va_start(ap, childname);
886e1ddb
AM
418
419 while (i < 255) {
ed100f44
AM
420 if ((attrname = va_arg(ap, const char *))) {
421 value = va_arg(ap, const char *);
422 }
423 if (attrname && value) {
424 names[i] = attrname;
425 vals[i] = value;
426 } else {
427 break;
428 }
429 i++;
430 }
431
432 va_end(ap);
433
434 if (!(childname && i)) {
435 return node;
436 }
886e1ddb 437
ed100f44
AM
438 for (p = switch_xml_child(node, childname); p; p = p->next) {
439 for (x = 0; x < i; x++) {
440 if (names[x] && vals[x]) {
441 const char *aname = switch_xml_attr(p, names[x]);
442
443 if (aname) {
444 if (*vals[x] == '!') {
445 const char *sval = vals[x] + 1;
0ac27178 446 if (strcasecmp(aname, sval)) {
ed100f44
AM
447 goto done;
448 }
449 } else {
450 if (!strcasecmp(aname, vals[x])) {
451 goto done;
452 }
453 }
454 }
455 }
456 }
457 }
458
886e1ddb 459 done:
ed100f44
AM
460
461 return p;
462}
463
de13f431 464/* returns the first child tag with the given name or NULL if not found */
59241895
MJ
465SWITCH_DECLARE(switch_xml_t) switch_xml_child(switch_xml_t xml, const char *name)
466{
467 xml = (xml) ? xml->child : NULL;
468 while (xml && strcmp(name, xml->name))
469 xml = xml->sibling;
470 return xml;
471}
472
de13f431 473/* returns the Nth tag with the same name in the same subsection or NULL if not found */
59241895
MJ
474switch_xml_t switch_xml_idx(switch_xml_t xml, int idx)
475{
476 for (; xml && idx; idx--)
477 xml = xml->next;
478 return xml;
479}
480
de13f431 481/* returns the value of the requested tag attribute or "" if not found */
59241895
MJ
482SWITCH_DECLARE(const char *) switch_xml_attr_soft(switch_xml_t xml, const char *attr)
483{
484 const char *ret = switch_xml_attr(xml, attr);
485
486 return ret ? ret : "";
487}
488
de13f431 489/* returns the value of the requested tag attribute or NULL if not found */
59241895
MJ
490SWITCH_DECLARE(const char *) switch_xml_attr(switch_xml_t xml, const char *attr)
491{
492 int i = 0, j = 1;
493 switch_xml_root_t root = (switch_xml_root_t) xml;
494
495 if (!xml || !xml->attr)
496 return NULL;
383ff711 497 while (xml->attr[i] && attr && strcmp(attr, xml->attr[i]))
59241895
MJ
498 i += 2;
499 if (xml->attr[i])
de13f431 500 return xml->attr[i + 1]; /* found attribute */
59241895
MJ
501
502 while (root->xml.parent)
de13f431 503 root = (switch_xml_root_t) root->xml.parent; /* root tag */
62ce8538 504
41557506
MJ
505 if (!root->attr) {
506 return NULL;
507 }
a2fcb419 508
383ff711 509 for (i = 0; root->attr[i] && xml->name && strcmp(xml->name, root->attr[i][0]); i++);
59241895 510 if (!root->attr[i])
de13f431 511 return NULL; /* no matching default attributes */
383ff711 512 while (root->attr[i][j] && attr && strcmp(attr, root->attr[i][j]))
59241895 513 j += 3;
de13f431 514 return (root->attr[i][j]) ? root->attr[i][j + 1] : NULL; /* found default */
59241895
MJ
515}
516
de13f431 517/* same as switch_xml_get but takes an already initialized va_list */
59241895
MJ
518static switch_xml_t switch_xml_vget(switch_xml_t xml, va_list ap)
519{
520 char *name = va_arg(ap, char *);
521 int idx = -1;
522
523 if (name && *name) {
524 idx = va_arg(ap, int);
525 xml = switch_xml_child(xml, name);
526 }
527 return (idx < 0) ? xml : switch_xml_vget(switch_xml_idx(xml, idx), ap);
528}
529
de13f431
BW
530/* Traverses the xml tree to retrieve a specific subtag. Takes a variable
531 length list of tag names and indexes. The argument list must be terminated
a2fcb419 532 by either an index of -1 or an empty string tag name. Example:
de13f431
BW
533 title = switch_xml_get(library, "shelf", 0, "book", 2, "title", -1);
534 This retrieves the title of the 3rd book on the 1st shelf of library.
535 Returns NULL if not found. */
59241895
MJ
536SWITCH_DECLARE(switch_xml_t) switch_xml_get(switch_xml_t xml,...)
537{
538 va_list ap;
539 switch_xml_t r;
540
541 va_start(ap, xml);
542 r = switch_xml_vget(xml, ap);
543 va_end(ap);
544 return r;
545}
546
de13f431 547/* returns a null terminated array of processing instructions for the given target */
59241895
MJ
548SWITCH_DECLARE(const char **) switch_xml_pi(switch_xml_t xml, const char *target)
549{
550 switch_xml_root_t root = (switch_xml_root_t) xml;
551 int i = 0;
552
55f2dc47 553 if (!root) {
59241895 554 return (const char **) SWITCH_XML_NIL;
55f2dc47
JK
555 }
556
557 while (root && root->xml.parent) {
de13f431 558 root = (switch_xml_root_t) root->xml.parent; /* root tag */
55f2dc47
JK
559 }
560
41557506
MJ
561 if (!root || !root->pi) {
562 return (const char **) SWITCH_XML_NIL;
563 }
55f2dc47
JK
564
565 while (root->pi[i] && strcmp(target, root->pi[i][0])) {
de13f431 566 i++; /* find target */
55f2dc47
JK
567 }
568
59241895
MJ
569 return (const char **) ((root->pi[i]) ? root->pi[i] + 1 : SWITCH_XML_NIL);
570}
571
de13f431 572/* set an error string and return root */
59241895
MJ
573static switch_xml_t switch_xml_err(switch_xml_root_t root, char *s, const char *err, ...)
574{
575 va_list ap;
576 int line = 1;
577 char *t, fmt[SWITCH_XML_ERRL];
578
41557506
MJ
579 if (!root || !root->s) {
580 return NULL;
581 }
582
59241895
MJ
583 for (t = root->s; t && t < s; t++)
584 if (*t == '\n')
585 line++;
586 switch_snprintf(fmt, SWITCH_XML_ERRL, "[error near line %d]: %s", line, err);
587
588 va_start(ap, err);
589 vsnprintf(root->err, SWITCH_XML_ERRL, fmt, ap);
590 va_end(ap);
591
592 return &root->xml;
593}
594
de13f431
BW
595/* Recursively decodes entity and character references and normalizes new lines
596 ent is a null terminated array of alternating entity names and values. set t
597 to '&' for general entity decoding, '%' for parameter entity decoding, 'c'
598 for cdata sections, ' ' for attribute normalization, or '*' for non-cdata
599 attribute normalization. Returns s, or if the decoded string is longer than
600 s, returns a malloced string that must be freed. */
59241895
MJ
601static char *switch_xml_decode(char *s, char **ent, char t)
602{
603 char *e, *r = s, *m = s;
48d6a5f6 604 unsigned long b, c, d, l;
59241895 605
886e1ddb 606 for (; *s; s++) { /* normalize line endings */
59241895
MJ
607 while (*s == '\r') {
608 *(s++) = '\n';
609 if (*s == '\n')
610 memmove(s, (s + 1), strlen(s));
611 }
612 }
613
614 for (s = r;;) {
e92fd635 615 while (*s && *s != '&' && (*s != '%' || t != '%') && !isspace((unsigned char) (*s)))
59241895
MJ
616 s++;
617
618 if (!*s)
619 break;
de13f431 620 else if (t != 'c' && !strncmp(s, "&#", 2)) { /* character reference */
48d6a5f6
PW
621 char *code = s + 2;
622 int base = 10;
623 if (*code == 'x') {
624 code++;
625 base = 16;
626 }
627 if (!isxdigit((int)*code)) { /* "&# 1;" and "&#-1;" are invalid */
628 s++;
629 continue;
630 }
631 c = strtoul(code, &e, base);
59241895
MJ
632 if (!c || *e != ';') {
633 s++;
634 continue;
886e1ddb
AM
635 }
636 /* not a character ref */
59241895 637 if (c < 0x80)
de13f431 638 *(s++) = (char) c; /* US-ASCII subset */
48d6a5f6
PW
639 else if (c > 0x7FFFFFFF) { /* out of UTF-8 range */
640 s++;
641 continue;
642 } else { /* multi-byte UTF-8 sequence */
59241895 643 for (b = 0, d = c; d; d /= 2)
886e1ddb 644 b++; /* number of bits in c */
de13f431 645 b = (b - 2) / 5; /* number of bytes in payload */
48d6a5f6 646 assert(b < 7); /* because c <= 0x7FFFFFFF */
de13f431 647 *(s++) = (char) ((0xFF << (7 - b)) | (c >> (6 * b))); /* head */
59241895 648 while (b)
de13f431 649 *(s++) = (char) (0x80 | ((c >> (6 * --b)) & 0x3F)); /* payload */
59241895
MJ
650 }
651
652 memmove(s, strchr(s, ';') + 1, strlen(strchr(s, ';')));
de13f431
BW
653 } else if ((*s == '&' && (t == '&' || t == ' ' || t == '*')) || (*s == '%' && t == '%')) { /* entity reference */
654 for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b])); b += 2); /* find entity in entity list */
59241895 655
de13f431 656 if (ent[b++]) { /* found a match */
48d6a5f6
PW
657 if ((c = (unsigned long) strlen(ent[b])) - 1 > (e = strchr(s, ';')) - s) {
658 l = (d = (unsigned long) (s - r)) + c + (unsigned long) strlen(e); /* new length */
59241895
MJ
659 if (l) {
660 if (r == m) {
350a739d
AM
661 char *tmp = (char *) switch_must_malloc(l);
662 r = strcpy(tmp, r);
59241895 663 } else {
350a739d 664 r = (char *) switch_must_realloc(r, l);
59241895
MJ
665 }
666 }
de13f431 667 e = strchr((s = r + d), ';'); /* fix up pointers */
59241895
MJ
668 }
669
de13f431
BW
670 memmove(s + c, e + 1, strlen(e)); /* shift rest of string */
671 strncpy(s, ent[b], c); /* copy in replacement text */
59241895 672 } else
de13f431 673 s++; /* not a known entity */
59241895
MJ
674 } else if ((t == ' ' || t == '*') && isspace((int) (*s)))
675 *(s++) = ' ';
676 else
de13f431 677 s++; /* no decoding needed */
59241895
MJ
678 }
679
de13f431 680 if (t == '*') { /* normalize spaces for non-cdata attributes */
59241895 681 for (s = r; *s; s++) {
48d6a5f6 682 if ((l = (unsigned long) strspn(s, " ")))
59241895
MJ
683 memmove(s, s + l, strlen(s + l) + 1);
684 while (*s && *s != ' ')
685 s++;
686 }
687 if (--s >= r && *s == ' ')
de13f431 688 *s = '\0'; /* trim any trailing space */
59241895
MJ
689 }
690 return r;
691}
692
de13f431 693/* called when parser finds start of new tag */
8e17dca0 694static void switch_xml_open_tag(switch_xml_root_t root, char *name, char *open_pos, char **attr)
59241895 695{
41557506
MJ
696 switch_xml_t xml;
697
698 if (!root || !root->cur) {
699 return;
700 }
701
702 xml = root->cur;
59241895
MJ
703
704 if (xml->name)
705 xml = switch_xml_add_child(xml, name, strlen(xml->txt));
706 else
de13f431 707 xml->name = name; /* first open tag */
59241895
MJ
708
709 xml->attr = attr;
de13f431 710 root->cur = xml; /* update tag insertion point */
8e17dca0 711 root->cur->open = open_pos;
59241895
MJ
712}
713
de13f431 714/* called when parser finds character content between open and closing tag */
59241895
MJ
715static void switch_xml_char_content(switch_xml_root_t root, char *s, switch_size_t len, char t)
716{
41557506 717 switch_xml_t xml;
59241895
MJ
718 char *m = s;
719 switch_size_t l;
720
41557506
MJ
721 if (!root || !root->cur) {
722 return;
723 }
724
725 xml = root->cur;
726
59241895 727 if (!xml || !xml->name || !len)
de13f431 728 return; /* sanity check */
59241895 729
de13f431 730 s[len] = '\0'; /* null terminate text (calling functions anticipate this) */
59241895
MJ
731 len = strlen(s = switch_xml_decode(s, root->ent, t)) + 1;
732
733 if (!*(xml->txt))
de13f431
BW
734 xml->txt = s; /* initial character content */
735 else { /* allocate our own memory and make a copy */
886e1ddb 736 if ((xml->flags & SWITCH_XML_TXTM)) { /* allocate some space */
350a739d 737 xml->txt = (char *) switch_must_realloc(xml->txt, (l = strlen(xml->txt)) + len);
59241895 738 } else {
350a739d
AM
739 char *tmp = (char *) switch_must_malloc((l = strlen(xml->txt)) + len);
740
741 xml->txt = strcpy(tmp, xml->txt);
59241895 742 }
de13f431 743 strcpy(xml->txt + l, s); /* add new char content */
59241895 744 if (s != m)
de13f431 745 free(s); /* free s if it was malloced by switch_xml_decode() */
59241895
MJ
746 }
747
748 if (xml->txt != m)
749 switch_xml_set_flag(xml, SWITCH_XML_TXTM);
750}
751
de13f431 752/* called when parser finds closing tag */
8e17dca0 753static switch_xml_t switch_xml_close_tag(switch_xml_root_t root, char *name, char *s, char *close_pos)
59241895 754{
41557506 755 if (!root || !root->cur || !root->cur->name || strcmp(name, root->cur->name))
59241895
MJ
756 return switch_xml_err(root, s, "unexpected closing tag </%s>", name);
757
8e17dca0 758 root->cur->close = close_pos;
59241895
MJ
759 root->cur = root->cur->parent;
760 return NULL;
761}
762
de13f431
BW
763/* checks for circular entity references, returns non-zero if no circular
764 references are found, zero otherwise */
59241895
MJ
765static int switch_xml_ent_ok(char *name, char *s, char **ent)
766{
767 int i;
768
769 for (;; s++) {
770 while (*s && *s != '&')
de13f431 771 s++; /* find next entity reference */
59241895
MJ
772 if (!*s)
773 return 1;
774 if (!strncmp(s + 1, name, strlen(name)))
de13f431 775 return 0; /* circular ref. */
59241895
MJ
776 for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2);
777 if (ent[i] && !switch_xml_ent_ok(name, ent[i + 1], ent))
778 return 0;
779 }
780}
781
de13f431 782/* called when the parser finds a processing instruction */
59241895
MJ
783static void switch_xml_proc_inst(switch_xml_root_t root, char *s, switch_size_t len)
784{
785 int i = 0, j = 1;
786 char *target = s;
787 char **sstmp;
788 char *stmp;
789
de13f431 790 s[len] = '\0'; /* null terminate instruction */
59241895 791 if (*(s += strcspn(s, SWITCH_XML_WS))) {
de13f431
BW
792 *s = '\0'; /* null terminate target */
793 s += strspn(s + 1, SWITCH_XML_WS) + 1; /* skip whitespace after target */
59241895
MJ
794 }
795
886e1ddb
AM
796 if (!root)
797 return;
59241895 798
de13f431 799 if (!strcmp(target, "xml")) { /* <?xml ... ?> */
59241895
MJ
800 if ((s = strstr(s, "standalone")) && !strncmp(s + strspn(s + 10, SWITCH_XML_WS "='\"") + 10, "yes", 3))
801 root->standalone = 1;
802 return;
803 }
804
f3c7c4d4 805 if (root->pi == (char ***)(SWITCH_XML_NIL) || !root->pi || !root->pi[0]) {
350a739d 806 root->pi = (char ***) switch_must_malloc(sizeof(char **));
886e1ddb 807 *(root->pi) = NULL; /* first pi */
59241895
MJ
808 }
809
810 while (root->pi[i] && strcmp(target, root->pi[i][0]))
de13f431
BW
811 i++; /* find target */
812 if (!root->pi[i]) { /* new target */
350a739d
AM
813 char ***ssstmp = (char ***) switch_must_realloc(root->pi, sizeof(char **) * (i + 2));
814
886e1ddb
AM
815 root->pi = ssstmp;
816 if (!root->pi)
817 return;
350a739d 818 root->pi[i] = (char **) switch_must_malloc(sizeof(char *) * 3);
59241895 819 root->pi[i][0] = target;
de13f431 820 root->pi[i][1] = (char *) (root->pi[i + 1] = NULL); /* terminate pi list */
350a739d 821 root->pi[i][2] = switch_must_strdup(""); /* empty document position list */
59241895
MJ
822 }
823
824 while (root->pi[i][j])
de13f431 825 j++; /* find end of instruction list for this target */
350a739d 826 sstmp = (char **) switch_must_realloc(root->pi[i], sizeof(char *) * (j + 3));
59241895 827 root->pi[i] = sstmp;
350a739d 828 stmp = (char *) switch_must_realloc(root->pi[i][j + 1], j + 1);
886e1ddb 829 root->pi[i][j + 2] = stmp;
59241895 830 strcpy(root->pi[i][j + 2] + j - 1, (root->xml.name) ? ">" : "<");
de13f431
BW
831 root->pi[i][j + 1] = NULL; /* null terminate pi list for this target */
832 root->pi[i][j] = s; /* set instruction */
59241895
MJ
833}
834
de13f431 835/* called when the parser finds an internal doctype subset */
59241895
MJ
836static short switch_xml_internal_dtd(switch_xml_root_t root, char *s, switch_size_t len)
837{
838 char q, *c, *t, *n = NULL, *v, **ent, **pe;
839 int i, j;
840 char **sstmp;
841
350a739d 842 pe = (char **) memcpy(switch_must_malloc(sizeof(SWITCH_XML_NIL)), SWITCH_XML_NIL, sizeof(SWITCH_XML_NIL));
886e1ddb 843
59241895
MJ
844 for (s[len] = '\0'; s;) {
845 while (*s && *s != '<' && *s != '%')
de13f431 846 s++; /* find next declaration */
59241895
MJ
847
848 if (!*s)
849 break;
886e1ddb 850 else if (!strncmp(s, "<!ENTITY", 8)) { /* parse entity definitions */
b59c28bd
AV
851 int use_pe;
852
de13f431 853 c = s += strspn(s + 8, SWITCH_XML_WS) + 8; /* skip white space separator */
886e1ddb 854 n = s + strspn(s, SWITCH_XML_WS "%"); /* find name */
de13f431 855 *(s = n + strcspn(n, SWITCH_XML_WS)) = ';'; /* append ; to name */
59241895 856
de13f431 857 v = s + strspn(s + 1, SWITCH_XML_WS) + 1; /* find value */
886e1ddb 858 if ((q = *(v++)) != '"' && q != '\'') { /* skip externals */
59241895
MJ
859 s = strchr(s, '>');
860 continue;
861 }
862
b59c28bd
AV
863 use_pe = (*c == '%');
864 for (i = 0, ent = (use_pe) ? pe : root->ent; ent[i]; i++);
350a739d 865 sstmp = (char **) switch_must_realloc(ent, (i + 3) * sizeof(char *)); /* space for next ent */
59241895 866 ent = sstmp;
b59c28bd 867 if (use_pe)
59241895
MJ
868 pe = ent;
869 else
870 root->ent = ent;
871
de13f431 872 *(++s) = '\0'; /* null terminate name */
59241895 873 if ((s = strchr(v, q)))
de13f431
BW
874 *(s++) = '\0'; /* null terminate value */
875 ent[i + 1] = switch_xml_decode(v, pe, '%'); /* set value */
876 ent[i + 2] = NULL; /* null terminate entity list */
877 if (!switch_xml_ent_ok(n, ent[i + 1], ent)) { /* circular reference */
59241895
MJ
878 if (ent[i + 1] != v)
879 free(ent[i + 1]);
880 switch_xml_err(root, v, "circular entity declaration &%s", n);
881 break;
882 } else
de13f431
BW
883 ent[i] = n; /* set entity name */
884 } else if (!strncmp(s, "<!ATTLIST", 9)) { /* parse default attributes */
885 t = s + strspn(s + 9, SWITCH_XML_WS) + 9; /* skip whitespace separator */
59241895
MJ
886 if (!*t) {
887 switch_xml_err(root, t, "unclosed <!ATTLIST");
888 break;
889 }
890 if (*(s = t + strcspn(t, SWITCH_XML_WS ">")) == '>')
891 continue;
892 else
de13f431 893 *s = '\0'; /* null terminate tag name */
e30c62f8 894 for (i = 0; root->attr[i] && n && strcmp(n, root->attr[i][0]); i++);
59241895 895
9300e0ad
AM
896 //while (*(n = ++s + strspn(s, SWITCH_XML_WS)) && *n != '>') {
897 // gcc 4.4 you are a creep
886e1ddb 898 for (;;) {
9300e0ad
AM
899 s++;
900 if (!(*(n = s + strspn(s, SWITCH_XML_WS)) && *n != '>')) {
901 break;
902 }
59241895 903 if (*(s = n + strcspn(n, SWITCH_XML_WS)))
de13f431 904 *s = '\0'; /* attr name */
59241895
MJ
905 else {
906 switch_xml_err(root, t, "malformed <!ATTLIST");
907 break;
908 }
909
de13f431 910 s += strspn(s + 1, SWITCH_XML_WS) + 1; /* find next token */
886e1ddb 911 c = (strncmp(s, "CDATA", 5)) ? (char *) "*" : (char *) " "; /* is it cdata? */
59241895
MJ
912 if (!strncmp(s, "NOTATION", 8))
913 s += strspn(s + 8, SWITCH_XML_WS) + 8;
914 s = (*s == '(') ? strchr(s, ')') : s + strcspn(s, SWITCH_XML_WS);
915 if (!s) {
916 switch_xml_err(root, t, "malformed <!ATTLIST");
917 break;
918 }
919
de13f431 920 s += strspn(s, SWITCH_XML_WS ")"); /* skip white space separator */
59241895
MJ
921 if (!strncmp(s, "#FIXED", 6))
922 s += strspn(s + 6, SWITCH_XML_WS) + 6;
de13f431 923 if (*s == '#') { /* no default value */
59241895
MJ
924 s += strcspn(s, SWITCH_XML_WS ">") - 1;
925 if (*c == ' ')
de13f431 926 continue; /* cdata is default, nothing to do */
59241895 927 v = NULL;
de13f431 928 } else if ((*s == '"' || *s == '\'') && /* default value */
59241895
MJ
929 (s = strchr(v = s + 1, *s)))
930 *s = '\0';
931 else {
932 switch_xml_err(root, t, "malformed <!ATTLIST");
933 break;
934 }
935
de13f431 936 if (!root->attr[i]) { /* new tag name */
350a739d
AM
937 root->attr = (!i) ? (char ***) switch_must_malloc(2 * sizeof(char **))
938 : (char ***) switch_must_realloc(root->attr, (i + 2) * sizeof(char **));
939 root->attr[i] = (char **) switch_must_malloc(2 * sizeof(char *));
de13f431 940 root->attr[i][0] = t; /* set tag name */
59241895
MJ
941 root->attr[i][1] = (char *) (root->attr[i + 1] = NULL);
942 }
943
de13f431 944 for (j = 1; root->attr[i][j]; j += 3); /* find end of list */
350a739d 945 sstmp = (char **) switch_must_realloc(root->attr[i], (j + 4) * sizeof(char *));
59241895
MJ
946
947 root->attr[i] = sstmp;
de13f431 948 root->attr[i][j + 3] = NULL; /* null terminate list */
886e1ddb 949 root->attr[i][j + 2] = c; /* is it cdata? */
de13f431 950 root->attr[i][j + 1] = (v) ? switch_xml_decode(v, root->ent, *c) : NULL;
886e1ddb 951 root->attr[i][j] = n; /* attribute name */
59241895
MJ
952 }
953 } else if (!strncmp(s, "<!--", 4))
886e1ddb
AM
954 s = strstr(s + 4, "-->"); /* comments */
955 else if (!strncmp(s, "<?", 2)) { /* processing instructions */
59241895
MJ
956 if ((s = strstr(c = s + 2, "?>")))
957 switch_xml_proc_inst(root, c, s++ - c);
958 } else if (*s == '<')
886e1ddb 959 s = strchr(s, '>'); /* skip other declarations */
59241895
MJ
960 else if (*(s++) == '%' && !root->standalone)
961 break;
962 }
963
964 free(pe);
965 return !*root->err;
966}
967
de13f431
BW
968/* Converts a UTF-16 string to UTF-8. Returns a new string that must be freed
969 or NULL if no conversion was needed. */
59241895
MJ
970static char *switch_xml_str2utf8(char **s, switch_size_t *len)
971{
972 char *u;
973 switch_size_t l = 0, sl, max = *len;
974 long c, d;
975 int b, be = (**s == '\xFE') ? 1 : (**s == '\xFF') ? 0 : -1;
976
977 if (be == -1)
de13f431 978 return NULL; /* not UTF-16 */
59241895 979
dca7940f
AV
980 if (*len <= 3)
981 return NULL;
982
350a739d 983 u = (char *) switch_must_malloc(max);
59241895 984 for (sl = 2; sl < *len - 1; sl += 2) {
de13f431 985 c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) /* UTF-16BE */
886e1ddb 986 : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF); /* UTF-16LE */
de13f431 987 if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) { /* high-half */
59241895
MJ
988 d = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
989 : (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
990 c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
991 }
992
993 while (l + 6 > max) {
994 char *tmp;
350a739d 995 tmp = (char *) switch_must_realloc(u, max += SWITCH_XML_BUFSIZE);
59241895
MJ
996 u = tmp;
997 }
998 if (c < 0x80)
de13f431
BW
999 u[l++] = (char) c; /* US-ASCII subset */
1000 else { /* multi-byte UTF-8 sequence */
59241895 1001 for (b = 0, d = c; d; d /= 2)
de13f431
BW
1002 b++; /* bits in c */
1003 b = (b - 2) / 5; /* bytes in payload */
1004 u[l++] = (char) ((0xFF << (7 - b)) | (c >> (6 * b))); /* head */
59241895 1005 while (b)
de13f431 1006 u[l++] = (char) (0x80 | ((c >> (6 * --b)) & 0x3F)); /* payload */
59241895
MJ
1007 }
1008 }
350a739d 1009 return *s = (char *) switch_must_realloc(u, *len = l);
59241895
MJ
1010}
1011
de13f431 1012/* frees a tag attribute list */
59241895
MJ
1013static void switch_xml_free_attr(char **attr)
1014{
e42ebbb3 1015 int i, c = 0;
59241895
MJ
1016 char *m;
1017
1018 if (!attr || attr == SWITCH_XML_NIL)
de13f431 1019 return; /* nothing to free */
e42ebbb3
AV
1020 while (attr[c])
1021 c += 2; /* find end of attribute list */
1022 m = attr[c + 1]; /* list of which names and values are malloced */
1023 for (i = c / 2 - 1; i >= 0 ; i--) {
59241895
MJ
1024 if (m[i] & SWITCH_XML_NAMEM)
1025 free(attr[i * 2]);
1026 if (m[i] & SWITCH_XML_TXTM)
1027 free(attr[(i * 2) + 1]);
1028 }
1029 free(m);
1030 free(attr);
1031}
1032
886e1ddb 1033SWITCH_DECLARE(switch_xml_t) switch_xml_parse_str_dynamic(char *s, switch_bool_t dup)
3b168bcb
MR
1034{
1035 switch_xml_root_t root;
5802cb94 1036 char *data;
886e1ddb 1037
5802cb94 1038 switch_assert(s);
350a739d 1039 data = dup ? switch_must_strdup(s) : s;
886e1ddb 1040
3b168bcb 1041 if ((root = (switch_xml_root_t) switch_xml_parse_str(data, strlen(data)))) {
886e1ddb 1042 root->dynamic = 1; /* Make sure we free the memory is switch_xml_free() */
3b168bcb
MR
1043 return &root->xml;
1044 } else {
5802cb94
MR
1045 if (dup) {
1046 free(data);
1047 }
3b168bcb
MR
1048 return NULL;
1049 }
1050}
886e1ddb 1051
6b6c83a7 1052/* parse the given xml string and return a switch_xml structure */
59241895
MJ
1053SWITCH_DECLARE(switch_xml_t) switch_xml_parse_str(char *s, switch_size_t len)
1054{
1055 switch_xml_root_t root = (switch_xml_root_t) switch_xml_new(NULL);
de13f431 1056 char q, e, *d, **attr, **a = NULL; /* initialize a to avoid compile warning */
59241895
MJ
1057 int l, i, j;
1058
1059 root->m = s;
1060 if (!len)
1061 return switch_xml_err(root, s, "root tag missing");
de13f431
BW
1062 root->u = switch_xml_str2utf8(&s, &len); /* convert utf-16 to utf-8 */
1063 root->e = (root->s = s) + len; /* record start and end of work area */
59241895 1064
de13f431
BW
1065 e = s[len - 1]; /* save end char */
1066 s[len - 1] = '\0'; /* turn end char into null terminator */
59241895
MJ
1067
1068 while (*s && *s != '<')
de13f431 1069 s++; /* find first tag */
59241895
MJ
1070 if (!*s)
1071 return switch_xml_err(root, s, "root tag missing");
1072
1073 for (;;) {
1074 attr = (char **) SWITCH_XML_NIL;
1075 d = ++s;
1076
886e1ddb 1077 if (isalpha((int) (*s)) || *s == '_' || *s == ':' || (int8_t) * s < '\0') { /* new tag */
59241895
MJ
1078 if (!root->cur)
1079 return switch_xml_err(root, d, "markup outside of root element");
1080
1081 s += strcspn(s, SWITCH_XML_WS "/>");
1082 while (isspace((int) (*s)))
886e1ddb 1083 *(s++) = '\0'; /* null terminate tag name */
59241895 1084
de13f431 1085 if (*s && *s != '/' && *s != '>') /* find tag in default attr list */
59241895
MJ
1086 for (i = 0; (a = root->attr[i]) && strcmp(a[0], d); i++);
1087
de13f431 1088 for (l = 0; *s && *s != '/' && *s != '>'; l += 2) { /* new attrib */
350a739d
AM
1089 attr = (l) ? (char **) switch_must_realloc(attr, (l + 4) * sizeof(char *))
1090 : (char **) switch_must_malloc(4 * sizeof(char *)); /* allocate space */
1091 attr[l + 3] = (l) ? (char *) switch_must_realloc(attr[l + 1], (l / 2) + 2)
1092 : (char *) switch_must_malloc(2); /* mem for list of maloced vals */
886e1ddb
AM
1093 strcpy(attr[l + 3] + (l / 2), " "); /* value is not malloced */
1094 attr[l + 2] = NULL; /* null terminate list */
1095 attr[l + 1] = (char *) ""; /* temporary attribute value */
1096 attr[l] = s; /* set attribute name */
59241895
MJ
1097
1098 s += strcspn(s, SWITCH_XML_WS "=/>");
1099 if (*s == '=' || isspace((int) (*s))) {
de13f431 1100 *(s++) = '\0'; /* null terminate tag attribute name */
59241895 1101 q = *(s += strspn(s, SWITCH_XML_WS "="));
de13f431 1102 if (q == '"' || q == '\'') { /* attribute value */
59241895
MJ
1103 attr[l + 1] = ++s;
1104 while (*s && *s != q)
1105 s++;
1106 if (*s)
de13f431 1107 *(s++) = '\0'; /* null terminate attribute val */
59241895
MJ
1108 else {
1109 switch_xml_free_attr(attr);
1110 return switch_xml_err(root, d, "missing %c", q);
1111 }
1112
1113 for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j += 3);
1114 attr[l + 1] = switch_xml_decode(attr[l + 1], root->ent, (a && a[j]) ? *a[j + 2] : ' ');
1115 if (attr[l + 1] < d || attr[l + 1] > s)
de13f431 1116 attr[l + 3][l / 2] = SWITCH_XML_TXTM; /* value malloced */
59241895
MJ
1117 }
1118 }
1119 while (isspace((int) (*s)))
1120 s++;
1121 }
1122
de13f431 1123 if (*s == '/') { /* self closing tag */
59241895
MJ
1124 *(s++) = '\0';
1125 if ((*s && *s != '>') || (!*s && e != '>')) {
1126 if (l)
1127 switch_xml_free_attr(attr);
1128 return switch_xml_err(root, d, "missing >");
1129 }
8e17dca0
CR
1130 switch_xml_open_tag(root, d, s + 1, attr);
1131 switch_xml_close_tag(root, d, s, NULL);
de13f431
BW
1132 } else if ((q = *s) == '>' || (!*s && e == '>')) { /* open tag */
1133 *s = '\0'; /* temporarily null terminate tag name */
8e17dca0 1134 switch_xml_open_tag(root, d, s, attr);
59241895
MJ
1135 *s = q;
1136 } else {
1137 if (l)
1138 switch_xml_free_attr(attr);
1139 return switch_xml_err(root, d, "missing >");
1140 }
de13f431 1141 } else if (*s == '/') { /* close tag */
8e17dca0 1142 char *close_pos = d - 1;
59241895
MJ
1143 s += strcspn(d = s + 1, SWITCH_XML_WS ">") + 1;
1144 if (!(q = *s) && e != '>')
1145 return switch_xml_err(root, d, "missing >");
de13f431 1146 *s = '\0'; /* temporarily null terminate tag name */
8e17dca0 1147 if (switch_xml_close_tag(root, d, s, close_pos))
59241895
MJ
1148 return &root->xml;
1149 if (isspace((int) (*s = q)))
1150 s += strspn(s, SWITCH_XML_WS);
de13f431 1151 } else if (!strncmp(s, "!--", 3)) { /* xml comment */
59241895
MJ
1152 if (!(s = strstr(s + 3, "--")) || (*(s += 2) != '>' && *s) || (!*s && e != '>'))
1153 return switch_xml_err(root, d, "unclosed <!--");
de13f431 1154 } else if (!strncmp(s, "![CDATA[", 8)) { /* cdata */
917d850b 1155 if ((s = strstr(s, "]]>"))) {
55f2dc47 1156 if (root->cur) {
917d850b
SD
1157 root->cur->flags |= SWITCH_XML_CDATA;
1158 }
59241895 1159 switch_xml_char_content(root, d + 8, (s += 2) - d - 10, 'c');
917d850b 1160 } else {
59241895 1161 return switch_xml_err(root, d, "unclosed <![CDATA[");
917d850b 1162 }
de13f431 1163 } else if (!strncmp(s, "!DOCTYPE", 8)) { /* dtd */
59241895
MJ
1164 for (l = 0; *s && ((!l && *s != '>') || (l && (*s != ']' || *(s + strspn(s + 1, SWITCH_XML_WS) + 1) != '>'))); l = (*s == '[') ? 1 : l)
1165 s += strcspn(s + 1, "[]>") + 1;
1166 if (!*s && e != '>')
1167 return switch_xml_err(root, d, "unclosed <!DOCTYPE");
1168 d = (l) ? strchr(d, '[') + 1 : d;
1169 if (l && !switch_xml_internal_dtd(root, d, s++ - d))
1170 return &root->xml;
de13f431 1171 } else if (*s == '?') { /* <?...?> processing instructions */
59241895
MJ
1172 do {
1173 s = strchr(s, '?');
1174 } while (s && *(++s) && *s != '>');
1175 if (!s || (!*s && e != '>'))
1176 return switch_xml_err(root, d, "unclosed <?");
1177 else
1178 switch_xml_proc_inst(root, d + 1, s - d - 2);
1179 } else
1180 return switch_xml_err(root, d, "unexpected <");
1181
1182 if (!s || !*s)
1183 break;
1184 *s = '\0';
1185 d = ++s;
de13f431 1186 if (*s && *s != '<') { /* tag character content */
59241895
MJ
1187 while (*s && *s != '<')
1188 s++;
1189 if (*s)
1190 switch_xml_char_content(root, d, s - d, '&');
1191 else
1192 break;
1193 } else if (!*s)
1194 break;
1195 }
1196
1197 if (!root->cur)
1198 return &root->xml;
1199 else if (!root->cur->name)
1200 return switch_xml_err(root, d, "root tag missing");
1201 else
1202 return switch_xml_err(root, d, "unclosed tag <%s>", root->cur->name);
1203}
1204
de13f431
BW
1205/* Wrapper for switch_xml_parse_str() that accepts a file stream. Reads the entire
1206 stream into memory and then parses it. For xml files, use switch_xml_parse_file()
1207 or switch_xml_parse_fd() */
59241895
MJ
1208SWITCH_DECLARE(switch_xml_t) switch_xml_parse_fp(FILE * fp)
1209{
1210 switch_xml_root_t root;
1211 switch_size_t l, len = 0;
1212 char *s;
1213
350a739d 1214 s = (char *) switch_must_malloc(SWITCH_XML_BUFSIZE);
df1ab07c 1215
59241895
MJ
1216 do {
1217 len += (l = fread((s + len), 1, SWITCH_XML_BUFSIZE, fp));
1218 if (l == SWITCH_XML_BUFSIZE) {
350a739d 1219 s = (char *) switch_must_realloc(s, len + SWITCH_XML_BUFSIZE);
59241895
MJ
1220 }
1221 } while (s && l == SWITCH_XML_BUFSIZE);
1222
55f2dc47 1223 if (!s) {
59241895 1224 return NULL;
55f2dc47
JK
1225 }
1226
1227 if (!(root = (switch_xml_root_t) switch_xml_parse_str(s, len))) {
1228 free(s);
1229
1230 return NULL;
1231 }
1232
de13f431 1233 root->dynamic = 1; /* so we know to free s in switch_xml_free() */
55f2dc47 1234
59241895
MJ
1235 return &root->xml;
1236}
1237
de13f431
BW
1238/* A wrapper for switch_xml_parse_str() that accepts a file descriptor. First
1239 attempts to mem map the file. Failing that, reads the file into memory.
1240 Returns NULL on failure. */
59241895
MJ
1241SWITCH_DECLARE(switch_xml_t) switch_xml_parse_fd(int fd)
1242{
1243 switch_xml_root_t root;
1244 struct stat st;
9cf864ba 1245 switch_ssize_t l;
59241895
MJ
1246 void *m;
1247
1248 if (fd < 0)
1249 return NULL;
59241895 1250
55f2dc47 1251 if (fstat(fd, &st) == -1 || !st.st_size) {
8f4e6392
AM
1252 return NULL;
1253 }
1254
350a739d
AM
1255 m = switch_must_malloc(st.st_size);
1256
9cf864ba
TC
1257 if (!(0<(l = read(fd, m, st.st_size)))
1258 || !(root = (switch_xml_root_t) switch_xml_parse_str((char *) m, l))) {
34bd0e5e 1259 free(m);
55f2dc47 1260
34bd0e5e 1261 return NULL;
59241895 1262 }
55f2dc47 1263
34bd0e5e
MOC
1264 root->dynamic = 1; /* so we know to free s in switch_xml_free() */
1265
59241895
MJ
1266 return &root->xml;
1267}
1268
531e0f2d 1269static char *expand_vars(char *buf, char *ebuf, switch_size_t elen, switch_size_t *newlen, const char **err)
59241895
MJ
1270{
1271 char *var, *val;
1272 char *rp = buf;
1273 char *wp = ebuf;
1274 char *ep = ebuf + elen - 1;
1275
56b6e954 1276 if (!strstr(rp, "$${")) {
59241895
MJ
1277 *newlen = strlen(buf);
1278 return buf;
1279 }
1280
1281 while (*rp && wp < ep) {
1282
1283 if (*rp == '$' && *(rp + 1) == '$' && *(rp + 2) == '{') {
3718cbc9 1284 char *e = switch_find_end_paren(rp + 2, '{', '}');
59241895
MJ
1285
1286 if (e) {
1287 rp += 3;
1288 var = rp;
1289 *e++ = '\0';
1290 rp = e;
4ae8282e 1291 if ((val = switch_core_get_variable_dup(var))) {
59241895
MJ
1292 char *p;
1293 for (p = val; p && *p && wp <= ep; p++) {
1294 *wp++ = *p;
1295 }
4ae8282e 1296 free(val);
59241895 1297 }
3718cbc9 1298 continue;
531e0f2d
AM
1299 } else if (err) {
1300 *err = "unterminated ${var}";
59241895
MJ
1301 }
1302 }
1303
1304 *wp++ = *rp++;
1305 }
d8e7897f
MJ
1306
1307 if (wp == ep) {
1308 return NULL;
1309 }
1310
59241895
MJ
1311 *wp++ = '\0';
1312 *newlen = strlen(ebuf);
1313
1314 return ebuf;
1315}
1316
c5204c21 1317static FILE *preprocess_exec(const char *cwd, const char *command, FILE *write_fd, int rlevel)
64a0bfc5
AM
1318{
1319#ifdef WIN32
16289ce9
JL
1320 FILE *fp = NULL;
1321 char buffer[1024];
64a0bfc5 1322
16289ce9
JL
1323 if (!command || !strlen(command)) goto end;
1324
1325 if ((fp = _popen(command, "r"))) {
1326 while (fgets(buffer, sizeof(buffer), fp) != NULL) {
1327 if (fwrite(buffer, 1, strlen(buffer), write_fd) <= 0) {
1328 break;
1329 }
1330 }
a2fcb419 1331
16289ce9
JL
1332 if(feof(fp)) {
1333 _pclose(fp);
1334 } else {
1335 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Exec failed to read the pipe of [%s] to the end\n", command);
1336 }
1337 } else {
1338 switch_snprintf(buffer, sizeof(buffer), "<!-- exec can not execute [%s] -->", command);
1339 fwrite( buffer, 1, strlen(buffer), write_fd);
1340 }
64a0bfc5
AM
1341#else
1342 int fds[2], pid = 0;
1343
1344 if (pipe(fds)) {
1345 goto end;
886e1ddb 1346 } else { /* good to go */
52eff945 1347 pid = switch_fork();
64a0bfc5 1348
886e1ddb 1349 if (pid < 0) { /* ok maybe not */
64a0bfc5
AM
1350 close(fds[0]);
1351 close(fds[1]);
1352 goto end;
886e1ddb 1353 } else if (pid) { /* parent */
64a0bfc5
AM
1354 char buf[1024] = "";
1355 int bytes;
1356 close(fds[1]);
1357 while ((bytes = read(fds[0], buf, sizeof(buf))) > 0) {
c5204c21 1358 if (fwrite(buf, 1, bytes, write_fd) <= 0) {
64a0bfc5
AM
1359 break;
1360 }
1361 }
1362 close(fds[0]);
dae2cb4a 1363 waitpid(pid, NULL, 0);
886e1ddb 1364 } else { /* child */
0f6a2bf8 1365 switch_close_extra_files(fds, 2);
64a0bfc5
AM
1366 close(fds[0]);
1367 dup2(fds[1], STDOUT_FILENO);
70ecd353 1368 switch_system(command, SWITCH_TRUE);
64a0bfc5
AM
1369 close(fds[1]);
1370 exit(0);
1371 }
1372 }
1373#endif
886e1ddb 1374 end:
64a0bfc5
AM
1375
1376 return write_fd;
886e1ddb 1377
64a0bfc5
AM
1378}
1379
2f48c631 1380static FILE *preprocess_glob(const char *cwd, const char *pattern, FILE *write_fd, int rlevel)
59241895
MJ
1381{
1382 char *full_path = NULL;
1383 char *dir_path = NULL, *e = NULL;
886e1ddb 1384 glob_t glob_data;
59241895 1385 size_t n;
a80c67e3 1386 int glob_return;
59241895
MJ
1387
1388 if (!switch_is_file_path(pattern)) {
1389 full_path = switch_mprintf("%s%s%s", cwd, SWITCH_PATH_SEPARATOR, pattern);
1390 pattern = full_path;
1391 }
886e1ddb 1392
a80c67e3
KR
1393 glob_return = glob(pattern, GLOB_ERR, NULL, &glob_data);
1394 if (glob_return == GLOB_NOSPACE || glob_return == GLOB_ABORTED) {
2f48c631 1395 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error including %s\n", pattern);
59241895 1396 goto end;
a80c67e3
KR
1397 } else if (glob_return == GLOB_NOMATCH) {
1398 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "No files to include at %s\n", pattern);
1399 goto end;
59241895
MJ
1400 }
1401
1402 for (n = 0; n < glob_data.gl_pathc; ++n) {
350a739d
AM
1403 dir_path = switch_must_strdup(glob_data.gl_pathv[n]);
1404
59241895
MJ
1405 if ((e = strrchr(dir_path, *SWITCH_PATH_SEPARATOR))) {
1406 *e = '\0';
1407 }
1408 if (preprocess(dir_path, glob_data.gl_pathv[n], write_fd, rlevel) < 0) {
59241895 1409 if (rlevel > 100) {
2d6161e8 1410 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error including %s (Maximum recursion limit reached)\n", pattern);
59241895 1411 }
59241895 1412 }
7ffcb0e6 1413 free(dir_path);
59241895 1414 }
886e1ddb 1415 globfree(&glob_data);
59241895 1416
a80c67e3 1417 end:
59241895
MJ
1418
1419 switch_safe_free(full_path);
1420
1421 return write_fd;
1422}
1423
c5204c21 1424static int preprocess(const char *cwd, const char *file, FILE *write_fd, int rlevel)
59241895 1425{
c5204c21 1426 FILE *read_fd = NULL;
59241895 1427 switch_size_t cur = 0, ml = 0;
c5204c21 1428 char *q, *cmd, *buf = NULL, *ebuf = NULL;
59241895 1429 char *tcmd, *targ;
531e0f2d 1430 int line = 0;
c5204c21 1431 switch_size_t len = 0, eblen = 0;
886e1ddb 1432
c5204c21
AM
1433 if (rlevel > 100) {
1434 return -1;
59241895
MJ
1435 }
1436
c5204c21
AM
1437 if (!(read_fd = fopen(file, "r"))) {
1438 const char *reason = strerror(errno);
959e672a 1439 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't open %s (%s)\n", file, reason);
59241895
MJ
1440 return -1;
1441 }
1442
c5204c21 1443 setvbuf(read_fd, (char *) NULL, _IOFBF, 65536);
a2fcb419 1444
c5204c21 1445 for(;;) {
59241895 1446 char *arg, *e;
531e0f2d 1447 const char *err = NULL;
c5204c21
AM
1448 char *bp;
1449
1450 switch_safe_free(ebuf);
1451
1452 if ((cur = switch_fp_read_dline(read_fd, &buf, &len)) <= 0) {
1453 break;
1454 }
1455
d8e7897f 1456 eblen = len * 2;
350a739d 1457 ebuf = switch_must_malloc(eblen);
c5204c21 1458 memset(ebuf, 0, eblen);
a2fcb419 1459
d8e7897f
MJ
1460 while (!(bp = expand_vars(buf, ebuf, eblen, &cur, &err))) {
1461 eblen *= 2;
350a739d 1462 ebuf = switch_must_realloc(ebuf, eblen);
d8e7897f
MJ
1463 memset(ebuf, 0, eblen);
1464 }
1465
531e0f2d 1466 line++;
886e1ddb 1467
4577ec87
AM
1468 if (err) {
1469 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error [%s] in file %s line %d\n", err, file, line);
531e0f2d 1470 }
59241895
MJ
1471
1472 /* we ignore <include> or </include> for the sake of validators as well as <?xml version="1.0"?> type stuff */
1473 if (strstr(buf, "<include>") || strstr(buf, "</include>") || strstr(buf, "<?")) {
1474 continue;
1475 }
1476
1477 if (ml) {
1478 if ((e = strstr(buf, "-->"))) {
1479 ml = 0;
1480 bp = e + 3;
1481 cur = strlen(bp);
1482 } else {
1483 continue;
1484 }
1485 }
1486
886e1ddb
AM
1487 if ((tcmd = (char *) switch_stristr("X-pre-process", bp))) {
1488 if (*(tcmd - 1) != '<') {
59241895
MJ
1489 continue;
1490 }
1491 if ((e = strstr(tcmd, "/>"))) {
0ac27178 1492 e += 2;
59241895 1493 *e = '\0';
c5204c21 1494 if (fwrite(e, 1, (unsigned) strlen(e), write_fd) != (int) strlen(e)) {
59241895
MJ
1495 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Short write!\n");
1496 }
1497 }
886e1ddb
AM
1498
1499 if (!(tcmd = (char *) switch_stristr("cmd", tcmd))) {
59241895
MJ
1500 continue;
1501 }
1502
886e1ddb 1503 if (!(tcmd = (char *) switch_stristr("=", tcmd))) {
59241895
MJ
1504 continue;
1505 }
1506
886e1ddb 1507 if (!(tcmd = (char *) switch_stristr("\"", tcmd))) {
59241895
MJ
1508 continue;
1509 }
886e1ddb 1510
59241895
MJ
1511 tcmd++;
1512
886e1ddb 1513
59241895
MJ
1514 if ((e = strchr(tcmd, '"'))) {
1515 *e++ = '\0';
1516 }
1517
886e1ddb 1518 if (!(targ = (char *) switch_stristr("data", e))) {
59241895
MJ
1519 continue;
1520 }
1521
886e1ddb 1522 if (!(targ = (char *) switch_stristr("=", targ))) {
59241895
MJ
1523 continue;
1524 }
1525
886e1ddb 1526 if (!(targ = (char *) switch_stristr("\"", targ))) {
59241895
MJ
1527 continue;
1528 }
1529
1530 targ++;
1531
1532 if ((e = strchr(targ, '"'))) {
1533 *e++ = '\0';
1534 }
886e1ddb 1535
59241895 1536 if (!strcasecmp(tcmd, "set")) {
886e1ddb 1537 char *name = (char *) targ;
59241895 1538 char *val = strchr(name, '=');
886e1ddb 1539
59241895
MJ
1540 if (val) {
1541 char *ve = val++;
1542 while (*val && *val == ' ') {
886e1ddb 1543 val++;
59241895
MJ
1544 }
1545 *ve-- = '\0';
1546 while (*ve && *ve == ' ') {
1547 *ve-- = '\0';
1548 }
1549 }
886e1ddb 1550
0ac27178 1551 if (val) {
59241895
MJ
1552 switch_core_set_variable(name, val);
1553 }
886e1ddb 1554
f30e40a8
KR
1555 } else if (!strcasecmp(tcmd, "exec-set")) {
1556 preprocess_exec_set(targ);
0629f95c
AV
1557 } else if (!strcasecmp(tcmd, "stun-set")) {
1558 preprocess_stun_set(targ);
4719d047
SD
1559 } else if (!strcasecmp(tcmd, "env-set")) {
1560 preprocess_env_set(targ);
59241895 1561 } else if (!strcasecmp(tcmd, "include")) {
2f48c631 1562 preprocess_glob(cwd, targ, write_fd, rlevel + 1);
64a0bfc5
AM
1563 } else if (!strcasecmp(tcmd, "exec")) {
1564 preprocess_exec(cwd, targ, write_fd, rlevel + 1);
59241895
MJ
1565 }
1566
1567 continue;
1568 }
886e1ddb 1569
59241895 1570 if ((cmd = strstr(bp, "<!--#"))) {
b39232c7 1571 if (fwrite(bp, 1, (unsigned) (cmd - bp), write_fd) != (unsigned) (cmd - bp)) {
59241895
MJ
1572 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Short write!\n");
1573 }
1574 if ((e = strstr(cmd, "-->"))) {
1575 *e = '\0';
1576 e += 3;
c5204c21 1577 if (fwrite(e, 1, (unsigned) strlen(e), write_fd) != (int) strlen(e)) {
59241895
MJ
1578 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Short write!\n");
1579 }
1580 } else {
1581 ml++;
1582 }
1583
1584 cmd += 5;
1585 if ((e = strchr(cmd, '\r')) || (e = strchr(cmd, '\n'))) {
1586 *e = '\0';
1587 }
1588
1589 if ((arg = strchr(cmd, ' '))) {
1590 *arg++ = '\0';
1591 if ((q = strchr(arg, '"'))) {
1592 char *qq = q + 1;
1593
1594 if ((qq = strchr(qq, '"'))) {
1595 *qq = '\0';
1596 arg = q + 1;
1597 }
1598 }
1599
1600 if (!strcasecmp(cmd, "set")) {
1601 char *name = arg;
1602 char *val = strchr(name, '=');
1603
1604 if (val) {
1605 char *ve = val++;
1606 while (*val && *val == ' ') {
1607 val++;
1608 }
1609 *ve-- = '\0';
1610 while (*ve && *ve == ' ') {
1611 *ve-- = '\0';
1612 }
1613 }
1614
0ac27178 1615 if (val) {
59241895
MJ
1616 switch_core_set_variable(name, val);
1617 }
1618
f30e40a8
KR
1619 } else if (!strcasecmp(cmd, "exec-set")) {
1620 preprocess_exec_set(arg);
0629f95c
AV
1621 } else if (!strcasecmp(cmd, "stun-set")) {
1622 preprocess_stun_set(arg);
59241895 1623 } else if (!strcasecmp(cmd, "include")) {
2f48c631 1624 preprocess_glob(cwd, arg, write_fd, rlevel + 1);
64a0bfc5
AM
1625 } else if (!strcasecmp(cmd, "exec")) {
1626 preprocess_exec(cwd, arg, write_fd, rlevel + 1);
59241895
MJ
1627 }
1628 }
1629
1630 continue;
1631 }
1632
c5204c21 1633 if (fwrite(bp, 1, (unsigned) cur, write_fd) != (int) cur) {
59241895
MJ
1634 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Short write!\n");
1635 }
c5204c21 1636
59241895
MJ
1637 }
1638
c5204c21
AM
1639 switch_safe_free(buf);
1640 switch_safe_free(ebuf);
1641
1642 fclose(read_fd);
1643
1644 return 0;
59241895
MJ
1645}
1646
1647SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file_simple(const char *file)
1648{
1649 int fd = -1;
1650 struct stat st;
9cf864ba 1651 switch_ssize_t l;
59241895
MJ
1652 void *m;
1653 switch_xml_root_t root;
1654
1655 if ((fd = open(file, O_RDONLY, 0)) > -1) {
55f2dc47 1656 if (fstat(fd, &st) == -1 || !st.st_size) {
49c1c359
JK
1657 close(fd);
1658 goto error;
1659 }
1660
350a739d
AM
1661 m = switch_must_malloc(st.st_size);
1662
49c1c359
JK
1663 if (!(0 < (l = read(fd, m, st.st_size)))) {
1664 free(m);
1665 close(fd);
1666 goto error;
1667 }
1668
1669 if (!(root = (switch_xml_root_t)switch_xml_parse_str((char*)m, l))) {
1670 free(m);
1671 close(fd);
1672 goto error;
1673 }
1674
59241895
MJ
1675 root->dynamic = 1;
1676 close(fd);
55f2dc47 1677
59241895
MJ
1678 return &root->xml;
1679 }
9da34921
AM
1680
1681 error:
1682
1683 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Parsing File [%s]\n", file);
886e1ddb 1684
59241895
MJ
1685 return NULL;
1686}
1687
1688SWITCH_DECLARE(switch_xml_t) switch_xml_parse_file(const char *file)
1689{
c5204c21
AM
1690 int fd = -1;
1691 FILE *write_fd = NULL;
59241895
MJ
1692 switch_xml_t xml = NULL;
1693 char *new_file = NULL;
f087248c 1694 char *new_file_tmp = NULL;
da7f9715 1695 const char *abs, *absw;
59241895 1696
886e1ddb
AM
1697 abs = strrchr(file, '/');
1698 absw = strrchr(file, '\\');
da7f9715
JL
1699 if (abs || absw) {
1700 abs > absw ? abs++ : (abs = ++absw);
59241895
MJ
1701 } else {
1702 abs = file;
1703 }
a2fcb419 1704
3ed59f1d 1705 switch_mutex_lock(FILE_LOCK);
886e1ddb 1706
59241895 1707 if (!(new_file = switch_mprintf("%s%s%s.fsxml", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, abs))) {
3ed59f1d 1708 goto done;
59241895
MJ
1709 }
1710
f087248c
BW
1711 if (!(new_file_tmp = switch_mprintf("%s%s%s.fsxml.tmp", SWITCH_GLOBAL_dirs.log_dir, SWITCH_PATH_SEPARATOR, abs))) {
1712 goto done;
1713 }
1714
1715 if ((write_fd = fopen(new_file_tmp, "w+")) == NULL) {
59241895
MJ
1716 goto done;
1717 }
1718
c5204c21
AM
1719 setvbuf(write_fd, (char *) NULL, _IOFBF, 65536);
1720
59241895 1721 if (preprocess(SWITCH_GLOBAL_dirs.conf_dir, file, write_fd, 0) > -1) {
c5204c21
AM
1722 fclose(write_fd);
1723 write_fd = NULL;
69cc7014
JL
1724 unlink (new_file);
1725
f087248c
BW
1726 if ( rename(new_file_tmp,new_file) ) {
1727 goto done;
1728 }
bb9afcb3 1729
59241895
MJ
1730 if ((fd = open(new_file, O_RDONLY, 0)) > -1) {
1731 if ((xml = switch_xml_parse_fd(fd))) {
1780e228 1732 if (strcmp(abs, SWITCH_GLOBAL_filenames.conf_name)) {
bd41ecc3
AM
1733 xml->free_path = new_file;
1734 new_file = NULL;
1735 }
59241895 1736 }
bb9afcb3 1737
59241895 1738 close(fd);
59241895
MJ
1739 }
1740 }
1741
1742 done:
3ed59f1d
AM
1743
1744 switch_mutex_unlock(FILE_LOCK);
1745
c5204c21
AM
1746 if (write_fd) {
1747 fclose(write_fd);
1748 write_fd = NULL;
59241895 1749 }
3ed59f1d 1750
f087248c 1751 switch_safe_free(new_file_tmp);
59241895 1752 switch_safe_free(new_file);
3ed59f1d 1753
59241895
MJ
1754 return xml;
1755}
1756
1757SWITCH_DECLARE(switch_status_t) switch_xml_locate(const char *section,
1758 const char *tag_name,
886e1ddb
AM
1759 const char *key_name,
1760 const char *key_value,
1761 switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_bool_t clone)
59241895
MJ
1762{
1763 switch_xml_t conf = NULL;
1764 switch_xml_t tag = NULL;
1765 switch_xml_t xml = NULL;
1766 switch_xml_binding_t *binding;
1767 uint8_t loops = 0;
9918f705 1768 switch_xml_section_t sections = BINDINGS ? switch_xml_parse_section_string(section) : 0;
59241895 1769
8ec9b8f7 1770 switch_thread_rwlock_rdlock(B_RWLOCK);
59241895
MJ
1771
1772 for (binding = BINDINGS; binding; binding = binding->next) {
59241895
MJ
1773 if (binding->sections && !(sections & binding->sections)) {
1774 continue;
1775 }
1776
1777 if ((xml = binding->function(section, tag_name, key_name, key_value, params, binding->user_data))) {
1778 const char *err = NULL;
1779
1780 err = switch_xml_error(xml);
df7637f6 1781 if (zstr(err)) {
59241895
MJ
1782 if ((conf = switch_xml_find_child(xml, "section", "name", "result"))) {
1783 switch_xml_t p;
1784 const char *aname;
1785
1786 if ((p = switch_xml_child(conf, "result"))) {
1787 aname = switch_xml_attr(p, "status");
1788 if (aname && !strcasecmp(aname, "not found")) {
1789 switch_xml_free(xml);
1790 xml = NULL;
1791 continue;
1792 }
1793 }
1794 }
1795 break;
1796 } else {
1797 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error[%s]\n", err);
1798 switch_xml_free(xml);
1799 xml = NULL;
1800 }
1801 }
1802 }
8ec9b8f7 1803 switch_thread_rwlock_unlock(B_RWLOCK);
59241895
MJ
1804
1805 for (;;) {
1806 if (!xml) {
1807 if (!(xml = switch_xml_root())) {
1808 *node = NULL;
1809 *root = NULL;
1810 return SWITCH_STATUS_FALSE;
1811 }
1812 }
1813
1814 if ((conf = switch_xml_find_child(xml, "section", "name", section)) && (tag = switch_xml_find_child(conf, tag_name, key_name, key_value))) {
93ec3d68 1815 if (clone) {
3b168bcb 1816 char *x = switch_xml_toxml(tag, SWITCH_FALSE);
93ec3d68 1817 switch_assert(x);
886e1ddb 1818 *node = *root = switch_xml_parse_str_dynamic(x, SWITCH_FALSE); /* x will be free()'d in switch_xml_free() */
93ec3d68
MJ
1819 switch_xml_free(xml);
1820 } else {
1821 *node = tag;
1822 *root = xml;
1823 }
59241895
MJ
1824 return SWITCH_STATUS_SUCCESS;
1825 } else {
1826 switch_xml_free(xml);
1827 xml = NULL;
1828 *node = NULL;
1829 *root = NULL;
1830 if (loops++ > 1) {
1831 break;
1832 }
1833 }
1834 }
1835
1836 return SWITCH_STATUS_FALSE;
1837}
1838
886e1ddb 1839SWITCH_DECLARE(switch_status_t) switch_xml_locate_domain(const char *domain_name, switch_event_t *params, switch_xml_t *root, switch_xml_t *domain)
59241895
MJ
1840{
1841 switch_event_t *my_params = NULL;
1842 switch_status_t status;
1843 *domain = NULL;
1844
1845 if (!params) {
003847dd 1846 switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
59241895
MJ
1847 switch_assert(my_params);
1848 switch_event_add_header_string(my_params, SWITCH_STACK_BOTTOM, "domain", domain_name);
1849 params = my_params;
1850 }
1851
93ec3d68 1852 status = switch_xml_locate("directory", "domain", "name", domain_name, root, domain, params, SWITCH_FALSE);
59241895
MJ
1853 if (my_params) {
1854 switch_event_destroy(&my_params);
1855 }
1856 return status;
1857}
1858
ed100f44 1859SWITCH_DECLARE(switch_status_t) switch_xml_locate_group(const char *group_name,
886e1ddb
AM
1860 const char *domain_name,
1861 switch_xml_t *root, switch_xml_t *domain, switch_xml_t *group, switch_event_t *params)
ed100f44
AM
1862{
1863 switch_status_t status = SWITCH_STATUS_FALSE;
1864 switch_event_t *my_params = NULL;
1865 switch_xml_t groups = NULL;
1866
1867 *root = NULL;
1868 *group = NULL;
1869 *domain = NULL;
1870
1871 if (!params) {
1872 switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
1873 switch_assert(my_params);
1874 params = my_params;
1875 }
1876
1877 if (group_name) {
1878 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "group_name", group_name);
1879 }
1880
1881 if (domain_name) {
1882 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "domain", domain_name);
1883 }
1884
1885 if ((status = switch_xml_locate_domain(domain_name, params, root, domain)) != SWITCH_STATUS_SUCCESS) {
1886 goto end;
1887 }
886e1ddb 1888
ed100f44
AM
1889 status = SWITCH_STATUS_FALSE;
1890
1891 if ((groups = switch_xml_child(*domain, "groups"))) {
1892 if ((*group = switch_xml_find_child(groups, "group", "name", group_name))) {
1893 status = SWITCH_STATUS_SUCCESS;
1894 }
1895 }
1896
886e1ddb 1897 end:
ed100f44
AM
1898
1899 if (my_params) {
1900 switch_event_destroy(&my_params);
1901 }
1902
1903 return status;
1904}
1905
de13f431
BW
1906static switch_status_t find_user_in_tag(switch_xml_t tag, const char *ip, const char *user_name,
1907 const char *key, switch_event_t *params, switch_xml_t *user)
ed100f44
AM
1908{
1909 const char *type = "!pointer";
1910 const char *val;
1911
1912 if (params && (val = switch_event_get_header(params, "user_type"))) {
1913 if (!strcasecmp(val, "any")) {
1914 type = NULL;
1915 } else {
1916 type = val;
1917 }
1918 }
1919
1920 if (ip) {
1921 if ((*user = switch_xml_find_child_multi(tag, "user", "ip", ip, "type", type, NULL))) {
1922 return SWITCH_STATUS_SUCCESS;
1923 }
886e1ddb 1924 }
ed100f44
AM
1925
1926 if (user_name) {
d18fa24a
MJ
1927 if (!strcasecmp(key, "id")) {
1928 if ((*user = switch_xml_find_child_multi(tag, "user", key, user_name, "number-alias", user_name, "type", type, NULL))) {
1929 return SWITCH_STATUS_SUCCESS;
1930 }
1931 } else {
1932 if ((*user = switch_xml_find_child_multi(tag, "user", key, user_name, "type", type, NULL))) {
ed100f44
AM
1933 return SWITCH_STATUS_SUCCESS;
1934 }
ed100f44
AM
1935 }
1936 }
886e1ddb 1937
ed100f44 1938 return SWITCH_STATUS_FALSE;
886e1ddb 1939
ed100f44
AM
1940}
1941
886e1ddb 1942SWITCH_DECLARE(switch_status_t) switch_xml_locate_user_in_domain(const char *user_name, switch_xml_t domain, switch_xml_t *user, switch_xml_t *ingroup)
bb974720
AM
1943{
1944 switch_xml_t group = NULL, groups = NULL, users = NULL;
1945 switch_status_t status = SWITCH_STATUS_FALSE;
886e1ddb 1946
bb974720
AM
1947 if ((groups = switch_xml_child(domain, "groups"))) {
1948 for (group = switch_xml_child(groups, "group"); group; group = group->next) {
1949 if ((users = switch_xml_child(group, "users"))) {
1950 if ((status = find_user_in_tag(users, NULL, user_name, "id", NULL, user)) == SWITCH_STATUS_SUCCESS) {
1951 if (ingroup) {
1952 *ingroup = group;
1953 }
1954 break;
1955 }
1956 }
1957 }
1064bb04
AM
1958 } else {
1959 if ((users = switch_xml_child(domain, "users"))) {
1960 status = find_user_in_tag(users, NULL, user_name, "id", NULL, user);
1961 } else {
1962 status = find_user_in_tag(domain, NULL, user_name, "id", NULL, user);
1963 }
bb974720
AM
1964 }
1965
1966 return status;
1967}
ed100f44 1968
c65da59d
AM
1969
1970SWITCH_DECLARE(switch_xml_t) switch_xml_dup(switch_xml_t xml)
1971{
1972 char *x = switch_xml_toxml(xml, SWITCH_FALSE);
a2fcb419 1973 return switch_xml_parse_str_dynamic(x, SWITCH_FALSE);
c65da59d
AM
1974}
1975
1976
a2fcb419 1977static void do_merge(switch_xml_t in, switch_xml_t src, const char *container, const char *tag_name)
c65da59d
AM
1978{
1979 switch_xml_t itag, tag, param, iparam, iitag;
1980
1981 if (!(itag = switch_xml_child(in, container))) {
1982 itag = switch_xml_add_child_d(in, container, 0);
1983 }
1984
1985 if ((tag = switch_xml_child(src, container))) {
1986 for (param = switch_xml_child(tag, tag_name); param; param = param->next) {
1987 const char *var = switch_xml_attr(param, "name");
1988 const char *val = switch_xml_attr(param, "value");
a2fcb419 1989
0147d4db 1990 switch_bool_t add_child = SWITCH_TRUE;
c65da59d
AM
1991
1992 for (iparam = switch_xml_child(itag, tag_name); iparam; iparam = iparam->next) {
1993 const char *ivar = switch_xml_attr(iparam, "name");
a2fcb419 1994
c65da59d 1995 if (var && ivar && !strcasecmp(var, ivar)) {
0147d4db 1996 add_child = SWITCH_FALSE;
c65da59d
AM
1997 break;
1998 }
1999 }
a2fcb419 2000
0147d4db 2001 if (add_child) {
c65da59d 2002 iitag = switch_xml_add_child_d(itag, tag_name, 0);
ea5db72a
BW
2003 switch_xml_set_attr_d(iitag, "name", var);
2004 switch_xml_set_attr_d(iitag, "value", val);
c65da59d
AM
2005 }
2006 }
2007 }
a2fcb419 2008
c65da59d
AM
2009}
2010
2011
2012SWITCH_DECLARE(void) switch_xml_merge_user(switch_xml_t user, switch_xml_t domain, switch_xml_t group)
2013{
f08c3309 2014 const char *domain_name = switch_xml_attr(domain, "name");
c65da59d
AM
2015
2016 do_merge(user, group, "params", "param");
2017 do_merge(user, group, "variables", "variable");
a6bffd38 2018 do_merge(user, group, "profile-variables", "variable");
c65da59d
AM
2019 do_merge(user, domain, "params", "param");
2020 do_merge(user, domain, "variables", "variable");
a6bffd38 2021 do_merge(user, domain, "profile-variables", "variable");
f08c3309
AM
2022
2023 if (!zstr(domain_name)) {
2024 switch_xml_set_attr_d(user, "domain-name", domain_name);
2025 }
c65da59d
AM
2026}
2027
2582bbcb
AM
2028SWITCH_DECLARE(uint32_t) switch_xml_clear_user_cache(const char *key, const char *user_name, const char *domain_name)
2029{
7151d6ac 2030 switch_hash_index_t *hi = NULL;
2582bbcb
AM
2031 void *val;
2032 const void *var;
2033 char mega_key[1024];
2034 int r = 0;
2035 switch_xml_t lookup;
15b8dfa8 2036 char *expires_val = NULL;
2582bbcb
AM
2037
2038 switch_mutex_lock(CACHE_MUTEX);
2039
39b3caac
AM
2040 if (key && user_name && !domain_name) {
2041 domain_name = switch_core_get_variable("domain");
2042 }
2043
2582bbcb
AM
2044 if (key && user_name && domain_name) {
2045 switch_snprintf(mega_key, sizeof(mega_key), "%s%s%s", key, user_name, domain_name);
2046
2047 if ((lookup = switch_core_hash_find(CACHE_HASH, mega_key))) {
2048 switch_core_hash_delete(CACHE_HASH, mega_key);
15b8dfa8 2049 if ((expires_val = switch_core_hash_find(CACHE_EXPIRES_HASH, mega_key))) {
a2fcb419 2050 switch_core_hash_delete(CACHE_EXPIRES_HASH, mega_key);
15b8dfa8
AM
2051 free(expires_val);
2052 expires_val = NULL;
a2fcb419 2053 }
2582bbcb
AM
2054 switch_xml_free(lookup);
2055 r++;
2056 }
a2fcb419 2057
2582bbcb 2058 } else {
a2fcb419 2059
7151d6ac 2060 while ((hi = switch_core_hash_first_iter( CACHE_HASH, hi))) {
804ef770 2061 switch_core_hash_this(hi, &var, NULL, &val);
2582bbcb
AM
2062 switch_xml_free(val);
2063 switch_core_hash_delete(CACHE_HASH, var);
2064 r++;
2582bbcb 2065 }
a2fcb419 2066
7151d6ac 2067 while ((hi = switch_core_hash_first_iter( CACHE_EXPIRES_HASH, hi))) {
804ef770 2068 switch_core_hash_this(hi, &var, NULL, &val);
a2fcb419
RC
2069 switch_safe_free(val);
2070 switch_core_hash_delete(CACHE_EXPIRES_HASH, var);
2071 }
7151d6ac
AM
2072
2073 switch_safe_free(hi);
2582bbcb
AM
2074 }
2075
2076 switch_mutex_unlock(CACHE_MUTEX);
a2fcb419 2077
2582bbcb 2078 return r;
a2fcb419 2079
2582bbcb
AM
2080}
2081
2082static switch_status_t switch_xml_locate_user_cache(const char *key, const char *user_name, const char *domain_name, switch_xml_t *user)
2083{
2084 char mega_key[1024];
2582bbcb 2085 switch_status_t status = SWITCH_STATUS_FALSE;
a2fcb419 2086 switch_xml_t lookup;
2582bbcb
AM
2087
2088 switch_snprintf(mega_key, sizeof(mega_key), "%s%s%s", key, user_name, domain_name);
2089
2090 switch_mutex_lock(CACHE_MUTEX);
2091 if ((lookup = switch_core_hash_find(CACHE_HASH, mega_key))) {
a2fcb419
RC
2092 char *expires_lookup = NULL;
2093
2094 if ((expires_lookup = switch_core_hash_find(CACHE_EXPIRES_HASH, mega_key))) {
2095 switch_time_t time_expires = 0;
2096 switch_time_t time_now = 0;
2097
2098 time_now = switch_micro_time_now();
2099 time_expires = atol(expires_lookup);
ab7ae9f7 2100 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cache Info\nTime Now:\t%ld\nExpires:\t%ld\n", (long)time_now, (long)time_expires);
a2fcb419
RC
2101 if (time_expires < time_now) {
2102 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Cache expired for %s@%s, doing fresh lookup\n", user_name, domain_name);
2103 } else {
2104 *user = switch_xml_dup(lookup);
2105 status = SWITCH_STATUS_SUCCESS;
2106 }
2107 } else {
2108 *user = switch_xml_dup(lookup);
2109 status = SWITCH_STATUS_SUCCESS;
2110 }
2582bbcb
AM
2111 }
2112 switch_mutex_unlock(CACHE_MUTEX);
2113
2114 return status;
2115}
2116
a2fcb419 2117static void switch_xml_user_cache(const char *key, const char *user_name, const char *domain_name, switch_xml_t user, switch_time_t expires)
2582bbcb
AM
2118{
2119 char mega_key[1024];
2120 switch_xml_t lookup;
a2fcb419 2121 char *expires_lookup;
2582bbcb
AM
2122
2123 switch_snprintf(mega_key, sizeof(mega_key), "%s%s%s", key, user_name, domain_name);
a2fcb419 2124
2582bbcb
AM
2125 switch_mutex_lock(CACHE_MUTEX);
2126 if ((lookup = switch_core_hash_find(CACHE_HASH, mega_key))) {
2127 switch_core_hash_delete(CACHE_HASH, mega_key);
2128 switch_xml_free(lookup);
2129 }
a2fcb419
RC
2130 if ((expires_lookup = switch_core_hash_find(CACHE_EXPIRES_HASH, mega_key))) {
2131 switch_core_hash_delete(CACHE_EXPIRES_HASH, mega_key);
2132 switch_safe_free(expires_lookup);
2133 }
2134 if (expires) {
781180ff
AV
2135 char *expires_val = (char *)switch_core_hash_insert_alloc(CACHE_EXPIRES_HASH, mega_key, 22);
2136 if (!snprintf(expires_val, 22, "%ld", (long)expires)) {
2137 switch_core_hash_delete(CACHE_EXPIRES_HASH, mega_key);
bdbefdcc 2138 switch_safe_free(expires_val);
a2fcb419
RC
2139 }
2140 }
2582bbcb
AM
2141 switch_core_hash_insert(CACHE_HASH, mega_key, switch_xml_dup(user));
2142 switch_mutex_unlock(CACHE_MUTEX);
2143}
2144
c65da59d
AM
2145SWITCH_DECLARE(switch_status_t) switch_xml_locate_user_merged(const char *key, const char *user_name, const char *domain_name,
2146 const char *ip, switch_xml_t *user, switch_event_t *params)
2147{
2148 switch_xml_t xml, domain, group, x_user, x_user_dup;
2149 switch_status_t status = SWITCH_STATUS_FALSE;
726b6076
AM
2150 char *kdup = NULL;
2151 char *keys[10] = {0};
2152 int i, nkeys;
c65da59d 2153
726b6076 2154 if (strchr(key, ':')) {
350a739d 2155 kdup = switch_must_strdup(key);
726b6076
AM
2156 nkeys = switch_split(kdup, ':', keys);
2157 } else {
2158 keys[0] = (char *)key;
2159 nkeys = 1;
2160 }
a2fcb419 2161
726b6076
AM
2162 for(i = 0; i < nkeys; i++) {
2163 if ((status = switch_xml_locate_user_cache(keys[i], user_name, domain_name, &x_user)) == SWITCH_STATUS_SUCCESS) {
2164 *user = x_user;
2165 break;
2166 } else if ((status = switch_xml_locate_user(keys[i], user_name, domain_name, ip, &xml, &domain, &x_user, &group, params)) == SWITCH_STATUS_SUCCESS) {
2167 const char *cacheable = NULL;
2168
2169 x_user_dup = switch_xml_dup(x_user);
2170 switch_xml_merge_user(x_user_dup, domain, group);
2171
2172 cacheable = switch_xml_attr(x_user_dup, "cacheable");
87c5c64c 2173 if (!zstr(cacheable)) {
726b6076
AM
2174 switch_time_t expires = 0;
2175 switch_time_t time_now = 0;
2176
2177 if (switch_is_number(cacheable)) {
2178 int cache_ms = atol(cacheable);
df1ab07c 2179 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "caching lookup for user %s@%s for %d milliseconds\n",
726b6076
AM
2180 user_name, domain_name, cache_ms);
2181 time_now = switch_micro_time_now();
2182 expires = time_now + (cache_ms * 1000);
2183 } else {
2184 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "caching lookup for user %s@%s indefinitely\n", user_name, domain_name);
2185 }
2186 switch_xml_user_cache(keys[i], user_name, domain_name, x_user_dup, expires);
a2fcb419 2187 }
726b6076
AM
2188 *user = x_user_dup;
2189 switch_xml_free(xml);
2190 break;
2582bbcb 2191 }
c65da59d
AM
2192 }
2193
726b6076
AM
2194 switch_safe_free(kdup);
2195
c65da59d
AM
2196 return status;
2197
2198}
2199
59241895
MJ
2200SWITCH_DECLARE(switch_status_t) switch_xml_locate_user(const char *key,
2201 const char *user_name,
886e1ddb
AM
2202 const char *domain_name,
2203 const char *ip,
59241895 2204 switch_xml_t *root,
886e1ddb 2205 switch_xml_t *domain, switch_xml_t *user, switch_xml_t *ingroup, switch_event_t *params)
59241895 2206{
5e5847f3 2207 switch_status_t status = SWITCH_STATUS_FALSE;
73279f01 2208 switch_event_t *my_params = NULL;
ed100f44 2209 switch_xml_t group = NULL, groups = NULL, users = NULL;
886e1ddb 2210
59241895
MJ
2211 *root = NULL;
2212 *user = NULL;
2213 *domain = NULL;
2214
772f9570
AM
2215 if (ingroup) {
2216 *ingroup = NULL;
2217 }
2218
5e5847f3 2219 if (!params) {
003847dd 2220 switch_event_create(&my_params, SWITCH_EVENT_REQUEST_PARAMS);
5e5847f3
AM
2221 switch_assert(my_params);
2222 params = my_params;
2223 }
59241895 2224
5e5847f3 2225 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "key", key);
59241895 2226
5e5847f3
AM
2227 if (user_name) {
2228 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "user", user_name);
2229 }
59241895 2230
5e5847f3
AM
2231 if (domain_name) {
2232 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "domain", domain_name);
59241895 2233 }
59241895 2234
5e5847f3
AM
2235 if (ip) {
2236 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "ip", ip);
2237 }
886e1ddb 2238
59241895 2239 if ((status = switch_xml_locate_domain(domain_name, params, root, domain)) != SWITCH_STATUS_SUCCESS) {
5e5847f3 2240 goto end;
59241895 2241 }
886e1ddb 2242
a2a748dd
AM
2243 status = SWITCH_STATUS_FALSE;
2244
ed100f44
AM
2245 if ((groups = switch_xml_child(*domain, "groups"))) {
2246 for (group = switch_xml_child(groups, "group"); group; group = group->next) {
2247 if ((users = switch_xml_child(group, "users"))) {
2248 if ((status = find_user_in_tag(users, ip, user_name, key, params, user)) == SWITCH_STATUS_SUCCESS) {
2249 if (ingroup) {
2250 *ingroup = group;
2251 }
2252 break;
2253 }
59241895
MJ
2254 }
2255 }
ed100f44 2256 }
59241895 2257
ed100f44 2258 if (status != SWITCH_STATUS_SUCCESS) {
1064bb04
AM
2259 if ((users = switch_xml_child(*domain, "users"))) {
2260 status = find_user_in_tag(users, ip, user_name, key, params, user);
2261 } else {
2262 status = find_user_in_tag(*domain, ip, user_name, key, params, user);
2263 }
59241895 2264 }
886e1ddb
AM
2265
2266 end:
5e5847f3
AM
2267
2268 if (my_params) {
2269 switch_event_destroy(&my_params);
2270 }
2271
bb9afcb3 2272 if (status != SWITCH_STATUS_SUCCESS && *root) {
e5f6e42e
AM
2273 switch_xml_free(*root);
2274 *root = NULL;
2275 *domain = NULL;
2276 }
2277
5e5847f3 2278 return status;
59241895
MJ
2279}
2280
2281SWITCH_DECLARE(switch_xml_t) switch_xml_root(void)
2282{
4714ed43 2283 switch_xml_t xml;
471bd6df 2284
4714ed43
AM
2285 switch_mutex_lock(REFLOCK);
2286 xml = MAIN_XML_ROOT;
2287 xml->refs++;
2288 switch_mutex_unlock(REFLOCK);
a2fcb419 2289
4714ed43 2290 return xml;
59241895
MJ
2291}
2292
7e9f64ee
AM
2293struct destroy_xml {
2294 switch_xml_t xml;
2295 switch_memory_pool_t *pool;
2296};
2297
2298static void *SWITCH_THREAD_FUNC destroy_thread(switch_thread_t *thread, void *obj)
2299{
2300 struct destroy_xml *dx = (struct destroy_xml *) obj;
2301 switch_memory_pool_t *pool = dx->pool;
2302 switch_xml_free(dx->xml);
2303 switch_core_destroy_memory_pool(&pool);
2304 return NULL;
2305}
2306
2307SWITCH_DECLARE(void) switch_xml_free_in_thread(switch_xml_t xml, int stacksize)
2308{
2309 switch_thread_t *thread;
886e1ddb 2310 switch_threadattr_t *thd_attr;
7e9f64ee
AM
2311 switch_memory_pool_t *pool = NULL;
2312 struct destroy_xml *dx;
2313
2314 switch_core_new_memory_pool(&pool);
2315
2316 switch_threadattr_create(&thd_attr, pool);
886e1ddb 2317 switch_threadattr_detach_set(thd_attr, 1);
de13f431 2318 /* TBD figure out how much space we need by looking at the xml_t when stacksize == 0 */
886e1ddb 2319 switch_threadattr_stacksize_set(thd_attr, stacksize);
7e9f64ee
AM
2320
2321 dx = switch_core_alloc(pool, sizeof(*dx));
2322 dx->pool = pool;
2323 dx->xml = xml;
2324
2325 switch_thread_create(&thread, thd_attr, destroy_thread, dx, pool);
7e9f64ee
AM
2326}
2327
59241895
MJ
2328static char not_so_threadsafe_error_buffer[256] = "";
2329
07a71592
AM
2330SWITCH_DECLARE(switch_status_t) switch_xml_set_root(switch_xml_t new_main)
2331{
2332 switch_xml_t old_root = NULL;
a2fcb419 2333
07a71592
AM
2334 switch_mutex_lock(REFLOCK);
2335
2336 old_root = MAIN_XML_ROOT;
2337 MAIN_XML_ROOT = new_main;
2338 switch_set_flag(MAIN_XML_ROOT, SWITCH_XML_ROOT);
2339 MAIN_XML_ROOT->refs++;
a2fcb419 2340
07a71592
AM
2341 if (old_root) {
2342 if (old_root->refs) {
2343 old_root->refs--;
2344 }
2345
2346 if (!old_root->refs) {
2347 switch_xml_free(old_root);
2348 }
2349 }
2350
2351 switch_mutex_unlock(REFLOCK);
2352
2353 return SWITCH_STATUS_SUCCESS;
2354}
2355
2356SWITCH_DECLARE(switch_status_t) switch_xml_set_open_root_function(switch_xml_open_root_function_t func, void *user_data)
2357{
2358 if (XML_LOCK) {
2359 switch_mutex_lock(XML_LOCK);
2360 }
a2fcb419 2361
07a71592
AM
2362 XML_OPEN_ROOT_FUNCTION = func;
2363 XML_OPEN_ROOT_FUNCTION_USER_DATA = user_data;
2364
2365 if (XML_LOCK) {
2366 switch_mutex_unlock(XML_LOCK);
2367 }
2368 return SWITCH_STATUS_SUCCESS;
2369}
2370
a2fcb419 2371SWITCH_DECLARE(switch_xml_t) switch_xml_open_root(uint8_t reload, const char **err)
07a71592
AM
2372{
2373 switch_xml_t root = NULL;
32437d04 2374 switch_event_t *event;
07a71592
AM
2375
2376 switch_mutex_lock(XML_LOCK);
2377
2378 if (XML_OPEN_ROOT_FUNCTION) {
2379 root = XML_OPEN_ROOT_FUNCTION(reload, err, XML_OPEN_ROOT_FUNCTION_USER_DATA);
2380 }
2381 switch_mutex_unlock(XML_LOCK);
2382
32437d04
AM
2383
2384 if (root) {
2385 if (switch_event_create(&event, SWITCH_EVENT_RELOADXML) == SWITCH_STATUS_SUCCESS) {
2386 if (switch_event_fire(&event) != SWITCH_STATUS_SUCCESS) {
2387 switch_event_destroy(&event);
2388 }
2389 }
2390 }
2391
07a71592
AM
2392 return root;
2393}
2394
3aaa6209 2395SWITCH_DECLARE_NONSTD(switch_xml_t) __switch_xml_open_root(uint8_t reload, const char **err, void *user_data)
59241895
MJ
2396{
2397 char path_buf[1024];
1ba98b02 2398 uint8_t errcnt = 0;
4714ed43 2399 switch_xml_t new_main, r = NULL;
59241895 2400
4714ed43
AM
2401 if (MAIN_XML_ROOT) {
2402 if (!reload) {
2403 r = switch_xml_root();
2404 goto done;
2405 }
59241895
MJ
2406 }
2407
bf607b0d 2408 switch_snprintf(path_buf, sizeof(path_buf), "%s%s%s", SWITCH_GLOBAL_dirs.conf_dir, SWITCH_PATH_SEPARATOR, SWITCH_GLOBAL_filenames.conf_name);
59241895
MJ
2409 if ((new_main = switch_xml_parse_file(path_buf))) {
2410 *err = switch_xml_error(new_main);
2411 switch_copy_string(not_so_threadsafe_error_buffer, *err, sizeof(not_so_threadsafe_error_buffer));
2412 *err = not_so_threadsafe_error_buffer;
df7637f6 2413 if (!zstr(*err)) {
59241895
MJ
2414 switch_xml_free(new_main);
2415 new_main = NULL;
2416 errcnt++;
2417 } else {
59241895 2418 *err = "Success";
07a71592 2419 switch_xml_set_root(new_main);
471bd6df 2420
59241895
MJ
2421 }
2422 } else {
2423 *err = "Cannot Open log directory or XML Root!";
2424 errcnt++;
2425 }
2426
59241895 2427 if (errcnt == 0) {
333019eb 2428 r = switch_xml_root();
59241895
MJ
2429 }
2430
07a71592 2431 done:
4714ed43 2432
333019eb 2433 return r;
59241895
MJ
2434}
2435
42c9df72
AM
2436SWITCH_DECLARE(switch_status_t) switch_xml_reload(const char **err)
2437{
2438 switch_xml_t xml_root;
a2fcb419 2439
42c9df72
AM
2440 if ((xml_root = switch_xml_open_root(1, err))) {
2441 switch_xml_free(xml_root);
2442 return SWITCH_STATUS_SUCCESS;
2443 }
2444
2445 return SWITCH_STATUS_GENERR;
2446}
2447
59241895
MJ
2448SWITCH_DECLARE(switch_status_t) switch_xml_init(switch_memory_pool_t *pool, const char **err)
2449{
2450 switch_xml_t xml;
2451 XML_MEMORY_POOL = pool;
2452 *err = "Success";
2453
2582bbcb 2454 switch_mutex_init(&CACHE_MUTEX, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
4714ed43
AM
2455 switch_mutex_init(&XML_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
2456 switch_mutex_init(&REFLOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
3ed59f1d 2457 switch_mutex_init(&FILE_LOCK, SWITCH_MUTEX_NESTED, XML_MEMORY_POOL);
804ef770
AM
2458 switch_core_hash_init(&CACHE_HASH);
2459 switch_core_hash_init(&CACHE_EXPIRES_HASH);
4714ed43 2460
8ec9b8f7 2461 switch_thread_rwlock_create(&B_RWLOCK, XML_MEMORY_POOL);
59241895
MJ
2462
2463 assert(pool != NULL);
2464
2465 if ((xml = switch_xml_open_root(FALSE, err))) {
2466 switch_xml_free(xml);
2467 return SWITCH_STATUS_SUCCESS;
2468 } else {
2469 return SWITCH_STATUS_FALSE;
2470 }
2471}
2472
2473SWITCH_DECLARE(switch_status_t) switch_xml_destroy(void)
2474{
333019eb 2475 switch_status_t status = SWITCH_STATUS_FALSE;
3ed59f1d 2476
2582bbcb 2477
4714ed43 2478 switch_mutex_lock(XML_LOCK);
3ed59f1d 2479 switch_mutex_lock(REFLOCK);
886e1ddb 2480
59241895
MJ
2481 if (MAIN_XML_ROOT) {
2482 switch_xml_t xml = MAIN_XML_ROOT;
2483 MAIN_XML_ROOT = NULL;
2484 switch_xml_free(xml);
333019eb 2485 status = SWITCH_STATUS_SUCCESS;
59241895
MJ
2486 }
2487
4714ed43 2488 switch_mutex_unlock(XML_LOCK);
3ed59f1d 2489 switch_mutex_unlock(REFLOCK);
333019eb 2490
2582bbcb
AM
2491 switch_xml_clear_user_cache(NULL, NULL, NULL);
2492
2493 switch_core_hash_destroy(&CACHE_HASH);
718d2341 2494 switch_core_hash_destroy(&CACHE_EXPIRES_HASH);
2582bbcb 2495
333019eb 2496 return status;
59241895
MJ
2497}
2498
2499SWITCH_DECLARE(switch_xml_t) switch_xml_open_cfg(const char *file_path, switch_xml_t *node, switch_event_t *params)
2500{
2501 switch_xml_t xml = NULL, cfg = NULL;
2502
2503 *node = NULL;
2504
2505 assert(MAIN_XML_ROOT != NULL);
2506
93ec3d68 2507 if (switch_xml_locate("configuration", "configuration", "name", file_path, &xml, &cfg, params, SWITCH_FALSE) == SWITCH_STATUS_SUCCESS) {
59241895
MJ
2508 *node = cfg;
2509 }
2510
2511 return xml;
2512
2513}
2514
de13f431
BW
2515/* Encodes ampersand sequences appending the results to *dst, reallocating *dst
2516 if length exceeds max. a is non-zero for attribute encoding. Returns *dst */
79079942 2517static char *switch_xml_ampencode(const char *s, switch_size_t len, char **dst, switch_size_t *dlen, switch_size_t *max, short a, switch_bool_t use_utf8_encoding)
59241895
MJ
2518{
2519 const char *e = NULL;
2520 int immune = 0;
4cd616cc
MOC
2521 int expecting_x_utf_8_char = 0;
2522 int unicode_char = 0x000000;
59241895 2523
886e1ddb
AM
2524 if (!(s && *s))
2525 return *dst;
59241895
MJ
2526
2527 if (len) {
2528 e = s + len;
2529 }
2530
2531 while (s != e) {
2532 while (*dlen + 10 > *max) {
350a739d 2533 *dst = (char *) switch_must_realloc(*dst, *max += SWITCH_XML_BUFSIZE);
59241895
MJ
2534 }
2535
2536 if (immune) {
2537 if (*s == '\0') {
2538 return *dst;
2539 }
2540 (*dst)[(*dlen)++] = *s;
886e1ddb 2541 } else
59241895 2542 switch (*s) {
886e1ddb
AM
2543 case '\0':
2544 return *dst;
2545 case '&':
2546 *dlen += sprintf(*dst + *dlen, "&amp;");
2547 break;
2548 case '<':
2549 if (*(s + 1) == '!') {
2550 (*dst)[(*dlen)++] = *s;
2551 immune++;
2552 break;
2553 }
2554 *dlen += sprintf(*dst + *dlen, "&lt;");
2555 break;
2556 case '>':
2557 *dlen += sprintf(*dst + *dlen, "&gt;");
59241895 2558 break;
886e1ddb
AM
2559 case '"':
2560 *dlen += sprintf(*dst + *dlen, (a) ? "&quot;" : "\"");
2561 break;
2562 case '\n':
2563 *dlen += sprintf(*dst + *dlen, (a) ? "&#xA;" : "\n");
2564 break;
2565 case '\t':
2566 *dlen += sprintf(*dst + *dlen, (a) ? "&#x9;" : "\t");
2567 break;
2568 case '\r':
2569 *dlen += sprintf(*dst + *dlen, "&#xD;");
2570 break;
2571 default:
79079942 2572 if (use_utf8_encoding && expecting_x_utf_8_char == 0 && ((*s >> 8) & 0x01)) {
4cd616cc
MOC
2573 int num = 1;
2574 for (;num<4;num++) {
2575 if (! ((*s >> (7-num)) & 0x01)) {
2576 break;
2577 }
2578 }
2579 switch (num) {
2580 case 2:
2581 unicode_char = *s & 0x1f;
2582 break;
2583 case 3:
2584 unicode_char = *s & 0x0f;
2585 break;
2586 case 4:
2587 unicode_char = *s & 0x07;
2588 break;
2589 default:
2590 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid UTF-8 Initial charactere, skip it\n");
2591 /* ERROR HERE */
2592 break;
2593 }
2594 expecting_x_utf_8_char = num - 1;
2595
79079942 2596 } else if (use_utf8_encoding && expecting_x_utf_8_char > 0) {
4cd616cc
MOC
2597 if (((*s >> 6) & 0x03) == 0x2) {
2598
2599 unicode_char = unicode_char << 6;
2600 unicode_char = unicode_char | (*s & 0x3f);
2601 } else {
2602 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid UTF-8 character to ampersand, skip it\n");
2603 expecting_x_utf_8_char = 0;
2604 break;
2605 }
2606 expecting_x_utf_8_char--;
2607 if (expecting_x_utf_8_char == 0) {
2608 *dlen += sprintf(*dst + *dlen, "&#x%X;", unicode_char);
2609 }
2610 } else {
2611 (*dst)[(*dlen)++] = *s;
2612 }
59241895 2613 }
59241895
MJ
2614 s++;
2615 }
2616 return *dst;
2617}
2618
2619#define XML_INDENT " "
de13f431
BW
2620/* Recursively converts each tag to xml appending it to *s. Reallocates *s if
2621 its length exceeds max. start is the location of the previous tag in the
2622 parent tag's character content. Returns *s. */
79079942 2623static char *switch_xml_toxml_r(switch_xml_t xml, char **s, switch_size_t *len, switch_size_t *max, switch_size_t start, char ***attr, uint32_t *count, int isroot, switch_bool_t use_utf8_encoding)
59241895
MJ
2624{
2625 int i, j;
9fa14d52
BW
2626 char *txt;
2627 switch_size_t off;
2628 uint32_t lcount;
287fd668 2629 uint32_t loops = 0;
9fa14d52 2630
886e1ddb 2631 tailrecurse:
9fa14d52 2632 off = 0;
287fd668
AM
2633 txt = "";
2634
2635 if (loops++) {
2636 isroot = 0;
2637 }
2638
2639 if (!isroot && xml->parent) {
2640 txt = (char *) xml->parent->txt;
2641 }
59241895 2642
de13f431 2643 /* parent character content up to this tag */
79079942 2644 *s = switch_xml_ampencode(txt + start, xml->off - start, s, len, max, 0, use_utf8_encoding);
59241895 2645
de13f431 2646 while (*len + strlen(xml->name) + 5 + (strlen(XML_INDENT) * (*count)) + 1 > *max) { /* reallocate s */
350a739d 2647 *s = (char *) switch_must_realloc(*s, *max += SWITCH_XML_BUFSIZE);
59241895
MJ
2648 }
2649
53ab0e2a 2650 if (*len && *(*s + (*len) - 1) == '>') {
de13f431 2651 *len += sprintf(*s + *len, "\n"); /* indent */
59241895
MJ
2652 }
2653 for (lcount = 0; lcount < *count; lcount++) {
de13f431 2654 *len += sprintf(*s + *len, "%s", XML_INDENT); /* indent */
59241895
MJ
2655 }
2656
de13f431
BW
2657 *len += sprintf(*s + *len, "<%s", xml->name); /* open tag */
2658 for (i = 0; xml->attr[i]; i += 2) { /* tag attributes */
59241895
MJ
2659 if (switch_xml_attr(xml, xml->attr[i]) != xml->attr[i + 1])
2660 continue;
de13f431 2661 while (*len + strlen(xml->attr[i]) + 7 + (strlen(XML_INDENT) * (*count)) > *max) { /* reallocate s */
350a739d 2662 *s = (char *) switch_must_realloc(*s, *max += SWITCH_XML_BUFSIZE);
59241895
MJ
2663 }
2664
2665 *len += sprintf(*s + *len, " %s=\"", xml->attr[i]);
79079942 2666 switch_xml_ampencode(xml->attr[i + 1], 0, s, len, max, 1, use_utf8_encoding);
59241895
MJ
2667 *len += sprintf(*s + *len, "\"");
2668 }
2669
2670 for (i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++);
de13f431 2671 for (j = 1; attr[i] && attr[i][j]; j += 3) { /* default attributes */
59241895 2672 if (!attr[i][j + 1] || switch_xml_attr(xml, attr[i][j]) != attr[i][j + 1])
de13f431
BW
2673 continue; /* skip duplicates and non-values */
2674 while (*len + strlen(attr[i][j]) + 8 + (strlen(XML_INDENT) * (*count)) > *max) { /* reallocate s */
350a739d 2675 *s = (char *) switch_must_realloc(*s, *max += SWITCH_XML_BUFSIZE);
59241895
MJ
2676 }
2677
2678 *len += sprintf(*s + *len, " %s=\"", attr[i][j]);
79079942 2679 switch_xml_ampencode(attr[i][j + 1], 0, s, len, max, 1, use_utf8_encoding);
59241895
MJ
2680 *len += sprintf(*s + *len, "\"");
2681 }
2682
2683 *len += sprintf(*s + *len, (xml->child || xml->txt) ? ">" : "/>\n");
2684
2685 if (xml->child) {
2686 (*count)++;
79079942 2687 *s = switch_xml_toxml_r(xml->child, s, len, max, 0, attr, count, 0, use_utf8_encoding);
59241895
MJ
2688
2689 } else {
79079942 2690 *s = switch_xml_ampencode(xml->txt, 0, s, len, max, 0, use_utf8_encoding); /* data */
59241895
MJ
2691 }
2692
de13f431 2693 while (*len + strlen(xml->name) + 5 + (strlen(XML_INDENT) * (*count)) > *max) { /* reallocate s */
350a739d 2694 *s = (char *) switch_must_realloc(*s, *max += SWITCH_XML_BUFSIZE);
886e1ddb 2695 }
59241895
MJ
2696
2697 if (xml->child || xml->txt) {
2698 if (*(*s + (*len) - 1) == '\n') {
2699 for (lcount = 0; lcount < *count; lcount++) {
de13f431 2700 *len += sprintf(*s + *len, "%s", XML_INDENT); /* indent */
59241895
MJ
2701 }
2702 }
f4e55fb1 2703 *len += sprintf(*s + (*len), "</%s>\n", xml->name); /* close tag */
59241895
MJ
2704 }
2705
2706 while (txt[off] && off < xml->off)
de13f431 2707 off++; /* make sure off is within bounds */
59241895 2708
287fd668 2709 if (!isroot && xml->ordered) {
9fa14d52
BW
2710 xml = xml->ordered;
2711 start = off;
2712 goto tailrecurse;
2713/*
79079942 2714 return switch_xml_toxml_r(xml->ordered, s, len, max, off, attr, count, use_utf8_encoding);
9fa14d52 2715*/
59241895
MJ
2716 } else {
2717 if (*count > 0)
2718 (*count)--;
79079942 2719 return switch_xml_ampencode(txt + off, 0, s, len, max, 0, use_utf8_encoding);
59241895
MJ
2720 }
2721}
2722
79079942 2723SWITCH_DECLARE(char *) switch_xml_toxml_nolock_ex(switch_xml_t xml, switch_bool_t prn_header, switch_bool_t use_utf8_encoding)
277c1141 2724{
350a739d
AM
2725 char *s = (char *) switch_must_malloc(SWITCH_XML_BUFSIZE);
2726
79079942 2727 return switch_xml_toxml_buf_ex(xml, s, SWITCH_XML_BUFSIZE, 0, prn_header, use_utf8_encoding);
277c1141 2728}
2729
79079942 2730SWITCH_DECLARE(char *) switch_xml_toxml_ex(switch_xml_t xml, switch_bool_t prn_header, switch_bool_t use_utf8_encoding)
59241895 2731{
4a520847 2732 char *r, *s;
277c1141 2733
350a739d 2734 s = (char *) switch_must_malloc(SWITCH_XML_BUFSIZE);
277c1141 2735
79079942 2736 r = switch_xml_toxml_buf_ex(xml, s, SWITCH_XML_BUFSIZE, 0, prn_header, use_utf8_encoding);
287fd668 2737
4a520847 2738 return r;
59241895
MJ
2739}
2740
79079942 2741SWITCH_DECLARE(char *) switch_xml_tohtml_ex(switch_xml_t xml, switch_bool_t prn_header, switch_bool_t use_utf8_encoding)
6b6c83a7
JL
2742{
2743 char *r, *s, *h;
2744 switch_size_t rlen = 0;
2745 switch_size_t len = SWITCH_XML_BUFSIZE;
350a739d
AM
2746
2747 s = (char *) switch_must_malloc(SWITCH_XML_BUFSIZE);
2748 h = (char *) switch_must_malloc(SWITCH_XML_BUFSIZE);
2749
79079942
SD
2750 r = switch_xml_toxml_buf_ex(xml, s, SWITCH_XML_BUFSIZE, 0, prn_header, use_utf8_encoding);
2751 h = switch_xml_ampencode(r, 0, &h, &rlen, &len, 1, use_utf8_encoding);
6b6c83a7 2752 switch_safe_free(r);
6b6c83a7
JL
2753 return h;
2754}
2755
2756/* converts a switch_xml structure back to xml, returning a string of xml data that
de13f431 2757 must be freed */
79079942 2758SWITCH_DECLARE(char *) switch_xml_toxml_buf_ex(switch_xml_t xml, char *buf, switch_size_t buflen, switch_size_t offset, switch_bool_t prn_header, switch_bool_t use_utf8_encoding)
59241895 2759{
287fd668 2760 switch_xml_t p = (xml) ? xml->parent : NULL;
59241895
MJ
2761 switch_xml_root_t root = (switch_xml_root_t) xml;
2762 switch_size_t len = 0, max = buflen;
350a739d 2763 char *s, *t, *n;
59241895
MJ
2764 int i, j, k;
2765 uint32_t count = 0;
886e1ddb 2766
59241895
MJ
2767 s = buf;
2768 assert(s != NULL);
2769 memset(s, 0, max);
2770 len += offset;
2771 if (prn_header) {
2772 len += sprintf(s + len, "<?xml version=\"1.0\"?>\n");
2773 }
886e1ddb 2774
59241895 2775 if (!xml || !xml->name) {
350a739d 2776 return (char *) switch_must_realloc(s, len + 1);
59241895
MJ
2777 }
2778
2779 while (root->xml.parent) {
de13f431 2780 root = (switch_xml_root_t) root->xml.parent; /* root tag */
59241895
MJ
2781 }
2782
de13f431 2783 for (i = 0; !p && root->pi[i]; i++) { /* pre-root processing instructions */
59241895
MJ
2784 for (k = 2; root->pi[i][k - 1]; k++);
2785 for (j = 1; (n = root->pi[i][j]); j++) {
2786 if (root->pi[i][k][j - 1] == '>') {
de13f431 2787 continue; /* not pre-root */
59241895
MJ
2788 }
2789 while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max) {
350a739d 2790 s = (char *) switch_must_realloc(s, max += SWITCH_XML_BUFSIZE);
59241895
MJ
2791 }
2792 len += sprintf(s + len, "<?%s%s%s?>", t, *n ? " " : "", n);
2793 }
2794 }
2795
79079942 2796 s = switch_xml_toxml_r(xml, &s, &len, &max, 0, root->attr, &count, 1, use_utf8_encoding);
59241895 2797
de13f431 2798 for (i = 0; !p && root->pi[i]; i++) { /* post-root processing instructions */
59241895
MJ
2799 for (k = 2; root->pi[i][k - 1]; k++);
2800 for (j = 1; (n = root->pi[i][j]); j++) {
2801 if (root->pi[i][k][j - 1] == '<') {
de13f431 2802 continue; /* not post-root */
59241895
MJ
2803 }
2804 while (len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max) {
350a739d 2805 s = (char *) switch_must_realloc(s, max += SWITCH_XML_BUFSIZE);
59241895
MJ
2806 }
2807 len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n);
2808 }
2809 }
2810
350a739d 2811 return (char *) switch_must_realloc(s, len + 1);
59241895
MJ
2812}
2813
de13f431 2814/* free the memory allocated for the switch_xml structure */
59241895
MJ
2815SWITCH_DECLARE(void) switch_xml_free(switch_xml_t xml)
2816{
9fa14d52 2817 switch_xml_root_t root;
59241895
MJ
2818 int i, j;
2819 char **a, *s;
9fa14d52 2820 switch_xml_t orig_xml;
4714ed43 2821 int refs = 0;
59241895 2822
4714ed43 2823 tailrecurse:
886e1ddb 2824 root = (switch_xml_root_t) xml;
f6f7f31c 2825 if (!xml) {
59241895 2826 return;
59241895
MJ
2827 }
2828
471bd6df 2829 if (switch_test_flag(xml, SWITCH_XML_ROOT)) {
4714ed43 2830 switch_mutex_lock(REFLOCK);
471bd6df 2831
4714ed43
AM
2832 if (xml->refs) {
2833 xml->refs--;
2834 refs = xml->refs;
471bd6df 2835 }
4714ed43 2836 switch_mutex_unlock(REFLOCK);
471bd6df 2837 }
471bd6df 2838
4714ed43 2839 if (refs) {
59241895
MJ
2840 return;
2841 }
2842
2843 if (xml->free_path) {
bd41ecc3
AM
2844 if (unlink(xml->free_path) != 0) {
2845 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to delete file [%s]\n", xml->free_path);
59241895
MJ
2846 }
2847 switch_safe_free(xml->free_path);
2848 }
2849
2850 switch_xml_free(xml->child);
886e1ddb 2851 /*switch_xml_free(xml->ordered); */
59241895 2852
de13f431 2853 if (!xml->parent) { /* free root tag allocations */
383ff711 2854#if (_MSC_VER >= 1400) // VC8+
886e1ddb 2855 __analysis_assume(sizeof(root->ent) > 44); /* tail recursion confuses code analysis */
383ff711 2856#endif
de13f431 2857 for (i = 10; root->ent[i]; i += 2) /* 0 - 9 are default entities (<>&"') */
59241895
MJ
2858 if ((s = root->ent[i + 1]) < root->s || s > root->e)
2859 free(s);
de13f431 2860 free(root->ent); /* free list of general entities */
59241895
MJ
2861
2862 for (i = 0; (a = root->attr[i]); i++) {
de13f431 2863 for (j = 1; a[j++]; j += 2) /* free malloced attribute values */
59241895
MJ
2864 if (a[j] && (a[j] < root->s || a[j] > root->e))
2865 free(a[j]);
2866 free(a);
2867 }
2868 if (root->attr[0])
de13f431 2869 free(root->attr); /* free default attribute list */
59241895
MJ
2870
2871 for (i = 0; root->pi[i]; i++) {
2872 for (j = 1; root->pi[i][j]; j++);
2873 free(root->pi[i][j + 1]);
2874 free(root->pi[i]);
2875 }
2876 if (root->pi[0])
de13f431 2877 free(root->pi); /* free processing instructions */
59241895
MJ
2878
2879 if (root->dynamic == 1)
de13f431 2880 free(root->m); /* malloced xml data */
59241895 2881 if (root->u)
de13f431 2882 free(root->u); /* utf8 conversion */
59241895
MJ
2883 }
2884
de13f431 2885 switch_xml_free_attr(xml->attr); /* tag attributes */
59241895 2886 if ((xml->flags & SWITCH_XML_TXTM))
de13f431 2887 free(xml->txt); /* character content */
59241895 2888 if ((xml->flags & SWITCH_XML_NAMEM))
de13f431 2889 free(xml->name); /* tag name */
9fa14d52
BW
2890 if (xml->ordered) {
2891 orig_xml = xml;
2892 xml = xml->ordered;
2893 free(orig_xml);
2894 goto tailrecurse;
2895 }
59241895
MJ
2896 free(xml);
2897}
2898
de13f431 2899/* return parser error message or empty string if none */
59241895
MJ
2900SWITCH_DECLARE(const char *) switch_xml_error(switch_xml_t xml)
2901{
2902 while (xml && xml->parent)
de13f431 2903 xml = xml->parent; /* find root tag */
59241895
MJ
2904 return (xml) ? ((switch_xml_root_t) xml)->err : "";
2905}
2906
de13f431 2907/* returns a new empty switch_xml structure with the given root tag name */
59241895
MJ
2908SWITCH_DECLARE(switch_xml_t) switch_xml_new(const char *name)
2909{
2910 static const char *ent[] = { "lt;", "&#60;", "gt;", "&#62;", "quot;", "&#34;",
2911 "apos;", "&#39;", "amp;", "&#38;", NULL
2912 };
350a739d
AM
2913 switch_xml_root_t root = (switch_xml_root_t) switch_must_malloc(sizeof(struct switch_xml_root));
2914
bbb8adf2 2915 memset(root, '\0', sizeof(struct switch_xml_root));
59241895
MJ
2916 root->xml.name = (char *) name;
2917 root->cur = &root->xml;
886e1ddb 2918 strcpy(root->err, root->xml.txt = (char *) "");
350a739d 2919 root->ent = (char **) memcpy(switch_must_malloc(sizeof(ent)), ent, sizeof(ent));
59241895
MJ
2920 root->attr = root->pi = (char ***) (root->xml.attr = SWITCH_XML_NIL);
2921 return &root->xml;
2922}
2923
6b6c83a7 2924/* inserts an existing tag into a switch_xml structure */
59241895
MJ
2925SWITCH_DECLARE(switch_xml_t) switch_xml_insert(switch_xml_t xml, switch_xml_t dest, switch_size_t off)
2926{
2927 switch_xml_t cur, prev, head;
2928
2929 xml->next = xml->sibling = xml->ordered = NULL;
2930 xml->off = off;
2931 xml->parent = dest;
2932
de13f431
BW
2933 if ((head = dest->child)) { /* already have sub tags */
2934 if (head->off <= off) { /* not first subtag */
59241895
MJ
2935 for (cur = head; cur->ordered && cur->ordered->off <= off; cur = cur->ordered);
2936 xml->ordered = cur->ordered;
2937 cur->ordered = xml;
de13f431 2938 } else { /* first subtag */
59241895
MJ
2939 xml->ordered = head;
2940 dest->child = xml;
2941 }
2942
de13f431
BW
2943 for (cur = head, prev = NULL; cur && strcmp(cur->name, xml->name); prev = cur, cur = cur->sibling); /* find tag type */
2944 if (cur && cur->off <= off) { /* not first of type */
59241895
MJ
2945 while (cur->next && cur->next->off <= off)
2946 cur = cur->next;
2947 xml->next = cur->next;
2948 cur->next = xml;
de13f431 2949 } else { /* first tag of this type */
59241895 2950 if (prev && cur)
de13f431
BW
2951 prev->sibling = cur->sibling; /* remove old first */
2952 xml->next = cur; /* old first tag is now next */
2953 for (cur = head, prev = NULL; cur && cur->off <= off; prev = cur, cur = cur->sibling); /* new sibling insert point */
59241895
MJ
2954 xml->sibling = cur;
2955 if (prev)
2956 prev->sibling = xml;
2957 }
2958 } else
de13f431 2959 dest->child = xml; /* only sub tag */
59241895
MJ
2960
2961 return xml;
2962}
2963
de13f431
BW
2964/* Adds a child tag. off is the offset of the child tag relative to the start
2965 of the parent tag's character content. Returns the child tag */
59241895
MJ
2966SWITCH_DECLARE(switch_xml_t) switch_xml_add_child(switch_xml_t xml, const char *name, switch_size_t off)
2967{
2968 switch_xml_t child;
2969
886e1ddb
AM
2970 if (!xml)
2971 return NULL;
350a739d
AM
2972 child = (switch_xml_t) switch_must_malloc(sizeof(struct switch_xml));
2973
bbb8adf2 2974 memset(child, '\0', sizeof(struct switch_xml));
59241895
MJ
2975 child->name = (char *) name;
2976 child->attr = SWITCH_XML_NIL;
2977 child->off = off;
2978 child->parent = xml;
886e1ddb 2979 child->txt = (char *) "";
59241895
MJ
2980
2981 return switch_xml_insert(child, xml, off);
2982}
2983
c776680c
CR
2984/* Adds a child tag. off is the offset of the child tag relative to the start
2985 of the parent tag's character content. Returns the child tag */
2986SWITCH_DECLARE(switch_xml_t) switch_xml_add_child_d(switch_xml_t xml, const char *name, switch_size_t off)
2987{
2988 if (!xml) return NULL;
2989 return switch_xml_set_flag(switch_xml_add_child(xml, strdup(name), off), SWITCH_XML_NAMEM);
2990}
2991
de13f431 2992/* sets the character content for the given tag and returns the tag */
59241895
MJ
2993SWITCH_DECLARE(switch_xml_t) switch_xml_set_txt(switch_xml_t xml, const char *txt)
2994{
2995 if (!xml)
2996 return NULL;
2997 if (xml->flags & SWITCH_XML_TXTM)
de13f431 2998 free(xml->txt); /* existing txt was malloced */
59241895
MJ
2999 xml->flags &= ~SWITCH_XML_TXTM;
3000 xml->txt = (char *) txt;
3001 return xml;
3002}
3003
c776680c
CR
3004/* sets the character content for the given tag and returns the tag */
3005SWITCH_DECLARE(switch_xml_t) switch_xml_set_txt_d(switch_xml_t xml, const char *txt)
3006{
3007 if (!xml) return NULL;
3008 return switch_xml_set_flag(switch_xml_set_txt(xml, strdup(txt)), SWITCH_XML_TXTM);
3009}
3010
de13f431
BW
3011/* Sets the given tag attribute or adds a new attribute if not found. A value
3012 of NULL will remove the specified attribute. Returns the tag given */
59241895
MJ
3013SWITCH_DECLARE(switch_xml_t) switch_xml_set_attr(switch_xml_t xml, const char *name, const char *value)
3014{
af5281e9 3015 int l = 0, c;
59241895
MJ
3016
3017 if (!xml)
3018 return NULL;
3019 while (xml->attr[l] && strcmp(xml->attr[l], name))
3020 l += 2;
de13f431 3021 if (!xml->attr[l]) { /* not found, add as new attribute */
59241895 3022 if (!value)
af5281e9 3023 return xml; /* nothing to do */
de13f431 3024 if (xml->attr == SWITCH_XML_NIL) { /* first attribute */
350a739d 3025 xml->attr = (char **) switch_must_malloc(4 * sizeof(char *));
53cd0690 3026 xml->attr[l + 1] = switch_must_strdup(""); /* empty list of malloced names/vals */
59241895 3027 } else {
350a739d 3028 xml->attr = (char **) switch_must_realloc(xml->attr, (l + 4) * sizeof(char *));
59241895
MJ
3029 }
3030
de13f431 3031 xml->attr[l] = (char *) name; /* set attribute name */
af5281e9 3032 xml->attr[l + 2] = NULL; /* null terminate attribute list */
350a739d 3033 xml->attr[l + 3] = (char *) switch_must_realloc(xml->attr[l + 1], (c = (int) strlen(xml->attr[l + 1])) + 2);
af5281e9 3034 strcpy(xml->attr[l + 3] + c, " "); /* set name/value as not malloced */
59241895 3035 if (xml->flags & SWITCH_XML_DUP)
af5281e9 3036 xml->attr[l + 3][c] = SWITCH_XML_NAMEM;
95fb8c77
AV
3037 c = l + 2; /* end of attribute list */
3038 } else {
3039 for (c = l; xml->attr[c]; c += 2); /* find end of attribute list */
3040
3041 if (xml->flags & SWITCH_XML_DUP)
3042 free((char*)name); /* name was strduped */
3043 if (xml->attr[c + 1][l / 2] & SWITCH_XML_TXTM)
3044 free(xml->attr[l + 1]); /* old val */
3045 }
59241895 3046
59241895 3047 if (xml->flags & SWITCH_XML_DUP)
af5281e9 3048 xml->attr[c + 1][l / 2] |= SWITCH_XML_TXTM;
59241895 3049 else
af5281e9 3050 xml->attr[c + 1][l / 2] &= ~SWITCH_XML_TXTM;
59241895 3051
af5281e9
AM
3052 if (value)
3053 xml->attr[l + 1] = (char *) value; /* set attribute value */
3054 else { /* remove attribute */
af5281e9
AM
3055 if (xml->attr[c + 1][l / 2] & SWITCH_XML_NAMEM)
3056 free(xml->attr[l]);
95fb8c77
AV
3057 c -= 2;
3058 if (c > 0) {
3059 memmove(xml->attr + l, xml->attr + l + 2, (c - l + 2) * sizeof(char*));
3060 xml->attr = (char**)switch_must_realloc(xml->attr, (c + 2) * sizeof(char*));
3061 memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1, (c / 2) - (l / 2)); /* fix list of which name/vals are malloced */
3062 xml->attr[c + 1][c / 2] = '\0';
3063 } else {
3064 /* last attribute removed, reset attribute list */
3065 free(xml->attr[3]);
3066 free(xml->attr);
3067 xml->attr = SWITCH_XML_NIL;
3068 }
af5281e9
AM
3069 }
3070 xml->flags &= ~SWITCH_XML_DUP; /* clear strdup() flag */
59241895
MJ
3071
3072 return xml;
3073}
3074
c776680c
CR
3075/* Sets the given tag attribute or adds a new attribute if not found. A value
3076 of NULL will remove the specified attribute. Returns the tag given */
3077SWITCH_DECLARE(switch_xml_t) switch_xml_set_attr_d(switch_xml_t xml, const char *name, const char *value)
3078{
3079 if (!xml) return NULL;
c35a3bb4 3080 return switch_xml_set_attr(switch_xml_set_flag(xml, SWITCH_XML_DUP), switch_must_strdup(name), switch_must_strdup(switch_str_nil(value)));
c776680c
CR
3081}
3082
3083/* Sets the given tag attribute or adds a new attribute if not found. A value
3084 of NULL will remove the specified attribute. Returns the tag given */
3085SWITCH_DECLARE(switch_xml_t) switch_xml_set_attr_d_buf(switch_xml_t xml, const char *name, const char *value)
3086{
3087 if (!xml) return NULL;
c35a3bb4 3088 return switch_xml_set_attr(switch_xml_set_flag(xml, SWITCH_XML_DUP), switch_must_strdup(name), switch_must_strdup(value));
c776680c
CR
3089}
3090
de13f431 3091/* sets a flag for the given tag and returns the tag */
59241895
MJ
3092SWITCH_DECLARE(switch_xml_t) switch_xml_set_flag(switch_xml_t xml, switch_xml_flag_t flag)
3093{
3094 if (xml)
3095 xml->flags |= flag;
3096 return xml;
3097}
3098
de13f431 3099/* removes a tag along with its subtags without freeing its memory */
59241895
MJ
3100SWITCH_DECLARE(switch_xml_t) switch_xml_cut(switch_xml_t xml)
3101{
3102 switch_xml_t cur;
3103
3104 if (!xml)
de13f431 3105 return NULL; /* nothing to do */
59241895 3106 if (xml->next)
de13f431 3107 xml->next->sibling = xml->sibling; /* patch sibling list */
59241895 3108
de13f431
BW
3109 if (xml->parent) { /* not root tag */
3110 cur = xml->parent->child; /* find head of subtag list */
59241895 3111 if (cur == xml)
de13f431
BW
3112 xml->parent->child = xml->ordered; /* first subtag */
3113 else { /* not first subtag */
59241895
MJ
3114 while (cur->ordered != xml)
3115 cur = cur->ordered;
de13f431 3116 cur->ordered = cur->ordered->ordered; /* patch ordered list */
59241895 3117
de13f431
BW
3118 cur = xml->parent->child; /* go back to head of subtag list */
3119 if (strcmp(cur->name, xml->name)) { /* not in first sibling list */
59241895
MJ
3120 while (strcmp(cur->sibling->name, xml->name))
3121 cur = cur->sibling;
de13f431 3122 if (cur->sibling == xml) { /* first of a sibling list */
59241895
MJ
3123 cur->sibling = (xml->next) ? xml->next : cur->sibling->sibling;
3124 } else
de13f431 3125 cur = cur->sibling; /* not first of a sibling list */
59241895
MJ
3126 }
3127
3128 while (cur->next && cur->next != xml)
3129 cur = cur->next;
3130 if (cur->next)
de13f431 3131 cur->next = cur->next->next; /* patch next list */
59241895
MJ
3132 }
3133 }
de13f431 3134 xml->ordered = xml->sibling = xml->next = NULL; /* prevent switch_xml_free() from clobbering ordered list */
59241895
MJ
3135 return xml;
3136}
3137
a2fcb419 3138SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond, int *offset, const char *tzname)
65a75664 3139{
09a734bb 3140
c9fcce08 3141 const char *xdt = switch_xml_attr(xcond, "date-time");
09a734bb
MJ
3142 const char *xyear = switch_xml_attr(xcond, "year");
3143 const char *xyday = switch_xml_attr(xcond, "yday");
3144 const char *xmon = switch_xml_attr(xcond, "mon");
3145 const char *xmday = switch_xml_attr(xcond, "mday");
3146 const char *xweek = switch_xml_attr(xcond, "week");
3147 const char *xmweek = switch_xml_attr(xcond, "mweek");
3148 const char *xwday = switch_xml_attr(xcond, "wday");
3149 const char *xhour = switch_xml_attr(xcond, "hour");
3150 const char *xminute = switch_xml_attr(xcond, "minute");
3151 const char *xminday = switch_xml_attr(xcond, "minute-of-day");
4ab8fa13 3152 const char *xtod = switch_xml_attr(xcond, "time-of-day");
65a75664 3153 const char *tzoff = switch_xml_attr(xcond, "tz-offset");
01dde19c 3154 const char *isdst = switch_xml_attr(xcond, "dst");
09a734bb 3155
01dde19c
AM
3156 int loffset = -1000;
3157 int eoffset = -1000;
3158 int dst = -1000;
09a734bb
MJ
3159 switch_time_t ts = switch_micro_time_now();
3160 int time_match = -1;
01dde19c
AM
3161 switch_time_exp_t tm, tm2;
3162
3163 if (!zstr(isdst)) {
3164 dst = switch_true(isdst);
3165 }
09a734bb 3166
65a75664
AM
3167 if (!zstr(tzoff) && switch_is_number(tzoff)) {
3168 loffset = atoi(tzoff);
65a75664
AM
3169 }
3170
01dde19c 3171 switch_time_exp_lt(&tm2, ts);
65a75664
AM
3172
3173 if (offset) {
01dde19c 3174 eoffset = *offset;
6d7e2799 3175 switch_time_exp_tz(&tm, ts, *offset * 3600);
a4a44fb1
AM
3176 } else if (!zstr(tzname)) {
3177 switch_time_exp_tz_name(tzname, &tm, ts);
65a75664 3178 } else {
01dde19c
AM
3179 tm = tm2;
3180 }
3181
3182 if (eoffset == -1000) {
3183 eoffset = tm.tm_gmtoff / 3600;
3184 }
3185
3186 if (loffset == -1000) {
3187 loffset = eoffset;
3188 }
3189
3190
3191 if (time_match && tzoff) {
3192 time_match = loffset == eoffset;
3193 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3194 "XML DateTime Check: TZOFFSET[%d] == %d (%s)\n", eoffset, loffset, time_match ? "PASS" : "FAIL");
3195
3196 }
3197
3198 if (time_match && dst > -1) {
3199 time_match = (tm2.tm_isdst > 0 && dst > 0);
3200 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
a2fcb419 3201 "XML DateTime Check: DST[%s] == %s (%s)\n",
01dde19c
AM
3202 tm2.tm_isdst > 0 ? "true" : "false", dst > 0 ? "true" : "false", time_match ? "PASS" : "FAIL");
3203
65a75664 3204 }
09a734bb 3205
c9fcce08
MOC
3206 if (time_match && xdt) {
3207 char tmpdate[80];
3208 switch_size_t retsize;
3209 switch_strftime(tmpdate, &retsize, sizeof(tmpdate), "%Y-%m-%d %H:%M:%S", &tm);
1b13e159 3210 time_match = switch_fulldate_cmp(xdt, &ts);
c9fcce08
MOC
3211 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
3212 "XML DateTime Check: date time[%s] =~ %s (%s)\n", tmpdate, xdt, time_match ? "PASS" : "FAIL");
3213 }
3214
09a734bb
MJ
3215 if (time_match && xyear) {
3216 int test = tm.tm_year + 1900;
3217 time_match = switch_number_cmp(xyear, test);
3218 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3219 "XML DateTime Check: year[%d] =~ %s (%s)\n", test, xyear, time_match ? "PASS" : "FAIL");
3220 }
3221
3222 if (time_match && xyday) {
3223 int test = tm.tm_yday + 1;
3224 time_match = switch_number_cmp(xyday, test);
3225 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3226 "XML DateTime Check: day of year[%d] =~ %s (%s)\n", test, xyday, time_match ? "PASS" : "FAIL");
3227 }
3228
3229 if (time_match && xmon) {
3230 int test = tm.tm_mon + 1;
3231 time_match = switch_number_cmp(xmon, test);
3232 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3233 "XML DateTime Check: month[%d] =~ %s (%s)\n", test, xmon, time_match ? "PASS" : "FAIL");
3234 }
3235
3236 if (time_match && xmday) {
3237 int test = tm.tm_mday;
3238 time_match = switch_number_cmp(xmday, test);
3239 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3240 "XML DateTime Check: day of month[%d] =~ %s (%s)\n", test, xmday, time_match ? "PASS" : "FAIL");
3241 }
3242
09a734bb
MJ
3243 if (time_match && xweek) {
3244 int test = (int) (tm.tm_yday / 7 + 1);
3245 time_match = switch_number_cmp(xweek, test);
3246 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3247 "XML DateTime Check: week of year[%d] =~ %s (%s)\n", test, xweek, time_match ? "PASS" : "FAIL");
3248 }
3249
3250 if (time_match && xmweek) {
3251 /* calculate the day of the week of the first of the month (0-6) */
3252 int firstdow = (int) (7 - (tm.tm_mday - (tm.tm_wday + 1)) % 7) % 7;
3253 /* calculate the week of the month (1-6)*/
3254 int test = (int) ceil((tm.tm_mday + firstdow) / 7.0);
3255 time_match = switch_number_cmp(xmweek, test);
3256 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3257 "XML DateTime: week of month[%d] =~ %s (%s)\n", test, xmweek, time_match ? "PASS" : "FAIL");
3258 }
3259
3260 if (time_match && xwday) {
3261 int test = tm.tm_wday + 1;
59ec8ced 3262 time_match = switch_dow_cmp(xwday, test);
09a734bb 3263 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
59ec8ced 3264 "XML DateTime Check: day of week[%s] =~ %s (%s)\n", switch_dow_int2str(test), xwday, time_match ? "PASS" : "FAIL");
09a734bb
MJ
3265 }
3266 if (time_match && xhour) {
3267 int test = tm.tm_hour;
3268 time_match = switch_number_cmp(xhour, test);
3269 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3270 "XML DateTime Check: hour[%d] =~ %s (%s)\n", test, xhour, time_match ? "PASS" : "FAIL");
3271 }
3272
3273 if (time_match && xminute) {
3274 int test = tm.tm_min;
3275 time_match = switch_number_cmp(xminute, test);
3276 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3277 "XML DateTime Check: minute[%d] =~ %s (%s)\n", test, xminute, time_match ? "PASS" : "FAIL");
3278 }
3279
3280 if (time_match && xminday) {
3281 int test = (tm.tm_hour * 60) + (tm.tm_min + 1);
3282 time_match = switch_number_cmp(xminday, test);
3283 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3284 "XML DateTime Check: minute of day[%d] =~ %s (%s)\n", test, xminday, time_match ? "PASS" : "FAIL");
3285 }
3286
4ab8fa13
MOC
3287 if (time_match && xtod) {
3288 int test = (tm.tm_hour * 60 * 60) + (tm.tm_min * 60) + tm.tm_sec;
3289 char tmpdate[10];
d09e6c60 3290 switch_snprintf(tmpdate, 10, "%d:%d:%d", tm.tm_hour, tm.tm_min, tm.tm_sec);
4ab8fa13
MOC
3291 time_match = switch_tod_cmp(xtod, test);
3292 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG9,
3293 "XML DateTime Check: time of day[%s] =~ %s (%s)\n", tmpdate, xtod, time_match ? "PASS" : "FAIL");
3294 }
3295
09a734bb
MJ
3296 return time_match;
3297}
3298
9d9b44e5 3299SWITCH_DECLARE(switch_status_t) switch_xml_locate_language_ex(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language) {
4137b360
MOC
3300 switch_status_t status = SWITCH_STATUS_FALSE;
3301
3302 if (switch_xml_locate("languages", NULL, NULL, NULL, root, node, params, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) {
3303 switch_xml_t sub_macros;
3304
3305 if (switch_xml_locate("phrases", NULL, NULL, NULL, root, node, params, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) {
3306 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of languages and phrases failed.\n");
3307 goto done;
3308 }
3309 if (!(sub_macros = switch_xml_child(*node, "macros"))) {
3310 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find macros tag.\n");
3311 switch_xml_free(*root);
3312 *root = NULL;
3313 *node = NULL;
3314 goto done;
3315 }
3316 if (!(*language = switch_xml_find_child(sub_macros, "language", "name", str_language))) {
3317 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find language %s.\n", str_language);
3318 switch_xml_free(*root);
3319 *root = NULL;
3320 *node = NULL;
3321 goto done;
3322 }
3323 *macros = *language;
3324 } else {
3325 if (!(*language = switch_xml_find_child(*node, "language", "name", str_language))) {
3326 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find language %s.\n", str_language);
3327 switch_xml_free(*root);
3328 *root = NULL;
3329 goto done;
3330 }
3331 if (!(*phrases = switch_xml_child(*language, "phrases"))) {
3332 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find phrases tag.\n");
3333 switch_xml_free(*root);
3334 *root = NULL;
3335 *node = NULL;
3336 *language = NULL;
3337 goto done;
3338 }
3339
3340 if (!(*macros = switch_xml_child(*phrases, "macros"))) {
3341 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't find macros tag.\n");
3342 switch_xml_free(*root);
3343 *root = NULL;
3344 *node = NULL;
3345 *language = NULL;
3346 *phrases = NULL;
3347 goto done;
3348 }
3349 }
3350 status = SWITCH_STATUS_SUCCESS;
3351
3352done:
3353 return status;
3354}
09a734bb 3355
9d9b44e5 3356SWITCH_DECLARE(switch_status_t) switch_xml_locate_language(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language) {
3357 switch_status_t status;
3358
3359 if ((status = switch_xml_locate_language_ex(root, node, params, language, phrases, macros, str_language)) != SWITCH_STATUS_SUCCESS) {
1c63aceb 3360 char *str_language_dup = strdup(str_language);
9d9b44e5 3361 char *secondary;
0ac27178 3362 switch_assert(str_language_dup);
1c63aceb 3363 if ((secondary = strchr(str_language_dup, '-'))) {
9d9b44e5 3364 *secondary++ = '\0';
1c63aceb
MJ
3365 switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
3366 "language %s not found. trying %s by removing %s\n", str_language, str_language_dup, secondary);
9d9b44e5 3367 switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "lang", str_language_dup);
3368 status = switch_xml_locate_language_ex(root, node, params, language, phrases, macros, str_language_dup);
3369 }
3370 switch_safe_free(str_language_dup);
3371 }
3372
3373 return status;
3374}
3375
59241895 3376#ifdef WIN32
a2fcb419
RC
3377/*
3378 * globbing functions for windows, part of libc on unix, this code was cut and paste from
59241895
MJ
3379 * freebsd lib and distilled a bit to work with windows
3380 */
3381
3382/*
3383 * Copyright (c) 1989, 1993
3384 * The Regents of the University of California. All rights reserved.
3385 *
3386 * This code is derived from software contributed to Berkeley by
3387 * Guido van Rossum.
3388 *
3389 * Redistribution and use in source and binary forms, with or without
3390 * modification, are permitted provided that the following conditions
3391 * are met:
3392 * 1. Redistributions of source code must retain the above copyright
3393 * notice, this list of conditions and the following disclaimer.
3394 * 2. Redistributions in binary form must reproduce the above copyright
3395 * notice, this list of conditions and the following disclaimer in the
3396 * documentation and/or other materials provided with the distribution.
3397 * 4. Neither the name of the University nor the names of its contributors
3398 * may be used to endorse or promote products derived from this software
3399 * without specific prior written permission.
3400 *
3401 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
3402 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3403 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3404 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
3405 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3406 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3407 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3408 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3409 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3410 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3411 * SUCH DAMAGE.
3412 */
3413
3414#define DOLLAR '$'
3415#define DOT '.'
3416#define EOS '\0'
3417#define LBRACKET '['
3418#define NOT '!'
3419#define QUESTION '?'
3420#define RANGE '-'
3421#define RBRACKET ']'
3422#define SEP '/'
e22f4233 3423#define WIN_SEP '/'
59241895
MJ
3424#define STAR '*'
3425#define TILDE '~'
3426#define UNDERSCORE '_'
3427#define LBRACE '{'
3428#define RBRACE '}'
3429#define SLASH '/'
3430#define COMMA ','
3431
3432#define M_QUOTE (char)0x80
3433#define M_PROTECT (char)0x40
3434#define M_MASK (char)0xff
3435#define M_ASCII (char)0x7f
3436
3437#define CHAR(c) ((char)((c)&M_ASCII))
3438#define META(c) ((char)((c)|M_QUOTE))
3439#define M_ALL META('*')
3440#define M_END META(']')
3441#define M_NOT META('!')
3442#define M_ONE META('?')
3443#define M_RNG META('-')
3444#define M_SET META('[')
3445#define ismeta(c) (((c)&M_QUOTE) != 0)
3446
3447#ifndef MAXPATHLEN
3448#define MAXPATHLEN 256
3449#endif
3450
886e1ddb
AM
3451static int compare(const void *, const void *);
3452static int glob0(const char *, glob_t *, size_t *);
3453static int glob1(char *, glob_t *, size_t *);
3454static int glob2(char *, char *, char *, char *, glob_t *, size_t *);
3455static int glob3(char *, char *, char *, char *, char *, glob_t *, size_t *);
3456static int globextend(const char *, glob_t *, size_t *);
3457static int match(char *, char *, char *);
59241895
MJ
3458
3459#pragma warning(push)
3460#pragma warning(disable:4310)
3461
886e1ddb 3462int glob(const char *pattern, int flags, int (*errfunc) (const char *, int), glob_t *pglob)
59241895
MJ
3463{
3464 const unsigned char *patnext;
5d4b5c3d 3465 size_t limit;
59241895
MJ
3466 char c;
3467 char *bufnext, *bufend, patbuf[MAXPATHLEN];
886e1ddb 3468
59241895
MJ
3469 patnext = (unsigned char *) pattern;
3470 if (!(flags & GLOB_APPEND)) {
3471 pglob->gl_pathc = 0;
3472 pglob->gl_pathv = NULL;
3473 if (!(flags & GLOB_DOOFFS))
3474 pglob->gl_offs = 0;
3475 }
3476 if (flags & GLOB_LIMIT) {
3477 limit = pglob->gl_matchc;
3478 if (limit == 0)
3479 limit = 9999999;
3480 } else
3481 limit = 0;
3482 pglob->gl_flags = flags & ~GLOB_MAGCHAR;
3483 pglob->gl_errfunc = errfunc;
3484 pglob->gl_matchc = 0;
886e1ddb 3485
59241895
MJ
3486 bufnext = patbuf;
3487 bufend = bufnext + MAXPATHLEN - 1;
3488 while (bufnext < bufend && (c = *patnext++) != EOS)
3489 *bufnext++ = c;
3490 *bufnext = EOS;
886e1ddb 3491
59241895
MJ
3492 return glob0(patbuf, pglob, &limit);
3493}
3494
3495/*
3496 * The main glob() routine: compiles the pattern (optionally processing
3497 * quotes), calls glob1() to do the real pattern matching, and finally
3498 * sorts the list (unless unsorted operation is requested). Returns 0
3499 * if things went well, nonzero if errors occurred.
3500 */
5d4b5c3d 3501static int glob0(const char *pattern, glob_t *pglob, size_t *limit)
59241895
MJ
3502{
3503 const char *qpatnext;
3504 int c, err;
5d4b5c3d 3505 size_t oldpathc;
59241895 3506 char *bufnext, patbuf[MAXPATHLEN];
886e1ddb 3507
59241895
MJ
3508 qpatnext = pattern;
3509 oldpathc = pglob->gl_pathc;
3510 bufnext = patbuf;
886e1ddb 3511
59241895
MJ
3512 /* We don't need to check for buffer overflow any more. */
3513 while ((c = *qpatnext++) != EOS) {
3514 switch (c) {
886e1ddb
AM
3515 case SEP:
3516 *bufnext++ = WIN_SEP;
3517 break;
3518 case LBRACKET:
3519 c = *qpatnext;
3520 if (c == NOT)
3521 ++qpatnext;
3522 if (*qpatnext == EOS || strchr((char *) qpatnext + 1, RBRACKET) == NULL) {
3523 *bufnext++ = LBRACKET;
59241895 3524 if (c == NOT)
886e1ddb 3525 --qpatnext;
59241895 3526 break;
886e1ddb
AM
3527 }
3528 *bufnext++ = M_SET;
3529 if (c == NOT)
3530 *bufnext++ = M_NOT;
3531 c = *qpatnext++;
3532 do {
59241895 3533 *bufnext++ = CHAR(c);
886e1ddb
AM
3534 if (*qpatnext == RANGE && (c = qpatnext[1]) != RBRACKET) {
3535 *bufnext++ = M_RNG;
3536 *bufnext++ = CHAR(c);
3537 qpatnext += 2;
3538 }
3539 } while ((c = *qpatnext++) != RBRACKET);
3540 pglob->gl_flags |= GLOB_MAGCHAR;
3541 *bufnext++ = M_END;
3542 break;
3543 case QUESTION:
3544 pglob->gl_flags |= GLOB_MAGCHAR;
3545 *bufnext++ = M_ONE;
3546 break;
3547 case STAR:
3548 pglob->gl_flags |= GLOB_MAGCHAR;
3549 /* collapse adjacent stars to one,
3550 * to avoid exponential behavior
3551 */
3552 if (bufnext == patbuf || bufnext[-1] != M_ALL)
3553 *bufnext++ = M_ALL;
3554 break;
3555 default:
3556 *bufnext++ = CHAR(c);
3557 break;
59241895
MJ
3558 }
3559 }
3560 *bufnext = EOS;
886e1ddb 3561
59241895 3562 if ((err = glob1(patbuf, pglob, limit)) != 0)
886e1ddb
AM
3563 return (err);
3564
59241895
MJ
3565 /*
3566 * If there was no match we are going to append the pattern
3567 * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
3568 * and the pattern did not contain any magic characters
3569 * GLOB_NOMAGIC is there just for compatibility with csh.
3570 */
3571 if (pglob->gl_pathc == oldpathc) {
886e1ddb
AM
3572 if (((pglob->gl_flags & GLOB_NOCHECK) || ((pglob->gl_flags & GLOB_NOMAGIC) && !(pglob->gl_flags & GLOB_MAGCHAR))))
3573 return (globextend(pattern, pglob, limit));
59241895 3574 else
886e1ddb 3575 return (GLOB_NOMATCH);
59241895
MJ
3576 }
3577 if (!(pglob->gl_flags & GLOB_NOSORT))
886e1ddb
AM
3578 qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc, pglob->gl_pathc - oldpathc, sizeof(char *), compare);
3579 return (0);
59241895
MJ
3580}
3581
3582static int compare(const void *p, const void *q)
3583{
886e1ddb 3584 return (strcmp(*(char **) p, *(char **) q));
59241895
MJ
3585}
3586
5d4b5c3d 3587static int glob1(char *pattern, glob_t *pglob, size_t *limit)
59241895
MJ
3588{
3589 char pathbuf[MAXPATHLEN];
886e1ddb 3590
59241895
MJ
3591 /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
3592 if (*pattern == EOS)
886e1ddb
AM
3593 return (0);
3594 return (glob2(pathbuf, pathbuf, pathbuf + MAXPATHLEN - 1, pattern, pglob, limit));
59241895
MJ
3595}
3596
3597/*
3598 * The functions glob2 and glob3 are mutually recursive; there is one level
3599 * of recursion for each segment in the pattern that contains one or more
3600 * meta characters.
3601 */
5d4b5c3d 3602static int glob2(char *pathbuf, char *pathend, char *pathend_last, char *pattern, glob_t *pglob, size_t *limit)
59241895
MJ
3603{
3604 struct stat sb;
3605 char *p, *q;
3606 int anymeta;
886e1ddb 3607
59241895
MJ
3608 /*
3609 * Loop over pattern segments until end of pattern or until
3610 * segment with meta character found.
3611 */
3612 for (anymeta = 0;;) {
886e1ddb 3613 if (*pattern == EOS) { /* End of pattern? */
59241895
MJ
3614 *pathend = EOS;
3615 if (stat(pathbuf, &sb))
886e1ddb
AM
3616 return (0);
3617
3618 if (((pglob->gl_flags & GLOB_MARK) && pathend[-1] != SEP && pathend[-1] != WIN_SEP) && (_S_IFDIR & sb.st_mode)) {
59241895
MJ
3619 if (pathend + 1 > pathend_last)
3620 return (GLOB_ABORTED);
3621 *pathend++ = WIN_SEP;
3622 *pathend = EOS;
3623 }
3624 ++pglob->gl_matchc;
886e1ddb 3625 return (globextend(pathbuf, pglob, limit));
59241895 3626 }
886e1ddb 3627
59241895
MJ
3628 /* Find end of next segment, copy tentatively to pathend. */
3629 q = pathend;
3630 p = pattern;
3631 while (*p != EOS && *p != SEP && *p != WIN_SEP) {
3632 if (ismeta(*p))
3633 anymeta = 1;
3634 if (q + 1 > pathend_last)
3635 return (GLOB_ABORTED);
3636 *q++ = *p++;
3637 }
886e1ddb
AM
3638
3639 if (!anymeta) { /* No expansion, do next segment. */
59241895
MJ
3640 pathend = q;
3641 pattern = p;
3642 while (*pattern == SEP || *pattern == WIN_SEP) {
3643 if (pathend + 1 > pathend_last)
3644 return (GLOB_ABORTED);
3645 *pathend++ = *pattern++;
3646 }
886e1ddb
AM
3647 } else /* Need expansion, recurse. */
3648 return (glob3(pathbuf, pathend, pathend_last, pattern, p, pglob, limit));
59241895
MJ
3649 }
3650 /* NOTREACHED */
3651}
3652
5d4b5c3d 3653static int glob3(char *pathbuf, char *pathend, char *pathend_last, char *pattern, char *restpattern, glob_t *pglob, size_t *limit)
59241895
MJ
3654{
3655 int err;
dd3075a2
AV
3656 fspr_dir_t *dirp;
3657 fspr_pool_t *pool;
886e1ddb 3658
dd3075a2 3659 fspr_pool_create(&pool, NULL);
886e1ddb 3660
59241895
MJ
3661 if (pathend > pathend_last)
3662 return (GLOB_ABORTED);
3663 *pathend = EOS;
3664 errno = 0;
886e1ddb 3665
dd3075a2 3666 if (fspr_dir_open(&dirp, pathbuf, pool) != APR_SUCCESS) {
59241895 3667 /* TODO: don't call for ENOENT or ENOTDIR? */
dd3075a2 3668 fspr_pool_destroy(pool);
59241895 3669 if (pglob->gl_errfunc) {
886e1ddb 3670 if (pglob->gl_errfunc(pathbuf, errno) || pglob->gl_flags & GLOB_ERR)
59241895
MJ
3671 return (GLOB_ABORTED);
3672 }
886e1ddb 3673 return (0);
59241895 3674 }
886e1ddb 3675
59241895 3676 err = 0;
886e1ddb 3677
59241895 3678 /* Search directory for matching names. */
886e1ddb 3679 while (dirp) {
dd3075a2 3680 fspr_finfo_t dp;
59241895
MJ
3681 unsigned char *sc;
3682 char *dc;
886e1ddb 3683
dd3075a2 3684 if (fspr_dir_read(&dp, APR_FINFO_NAME, dirp) != APR_SUCCESS)
59241895 3685 break;
d0688264 3686 if (!(dp.valid & APR_FINFO_NAME) || !(dp.name) || !strlen(dp.name))
59241895 3687 break;
886e1ddb 3688
59241895
MJ
3689 /* Initial DOT must be matched literally. */
3690 if (dp.name[0] == DOT && *pattern != DOT)
3691 continue;
3692 dc = pathend;
3693 sc = (unsigned char *) dp.name;
886e1ddb 3694
59241895 3695 while (dc < pathend_last && (*dc++ = *sc++) != EOS);
886e1ddb 3696
59241895
MJ
3697 if (!match(pathend, pattern, restpattern)) {
3698 *pathend = EOS;
3699 continue;
3700 }
886e1ddb 3701 err = glob2(pathbuf, --dc, pathend_last, restpattern, pglob, limit);
59241895
MJ
3702 if (err)
3703 break;
3704 }
886e1ddb
AM
3705
3706 if (dirp)
dd3075a2
AV
3707 fspr_dir_close(dirp);
3708 fspr_pool_destroy(pool);
886e1ddb 3709 return (err);
59241895
MJ
3710}
3711
3712
3713/*
ff3f04f1 3714 * Extend the gl_pathv member of a glob_t structure to accommodate a new item,
59241895
MJ
3715 * add the new item, and update gl_pathc.
3716 *
3717 * This assumes the BSD realloc, which only copies the block when its size
3718 * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
3719 * behavior.
3720 *
3721 * Return 0 if new item added, error code if memory couldn't be allocated.
3722 *
3723 * Invariant of the glob_t structure:
3724 * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
3725 * gl_pathv points to (gl_offs + gl_pathc + 1) items.
3726 */
5d4b5c3d 3727static int globextend(const char *path, glob_t *pglob, size_t *limit)
59241895
MJ
3728{
3729 char **pathv;
886e1ddb 3730 char *copy;
5d4b5c3d
RJ
3731 size_t i;
3732 size_t newsize, len;
59241895 3733 const char *p;
886e1ddb 3734
1bbf3a82 3735 if (*limit && pglob->gl_pathc > *limit) {
59241895
MJ
3736 errno = 0;
3737 return (GLOB_NOSPACE);
3738 }
886e1ddb 3739
59241895 3740 newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
350a739d 3741 pathv = pglob->gl_pathv ? switch_must_realloc((char *) pglob->gl_pathv, newsize) : switch_must_malloc(newsize);
886e1ddb 3742
59241895
MJ
3743 if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
3744 /* first time around -- clear initial gl_offs items */
3745 pathv += pglob->gl_offs;
886e1ddb 3746 for (i = pglob->gl_offs; i-- > 0;)
59241895
MJ
3747 *--pathv = NULL;
3748 }
3749 pglob->gl_pathv = pathv;
886e1ddb 3750
59241895
MJ
3751 for (p = path; *p++;)
3752 continue;
886e1ddb 3753 len = (size_t) (p - path);
350a739d
AM
3754 copy = switch_must_malloc(len);
3755 memcpy(copy, path, len);
3756 pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
59241895 3757 pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
886e1ddb 3758 return (copy == NULL ? GLOB_NOSPACE : 0);
59241895
MJ
3759}
3760
3761/*
3762 * pattern matching function for filenames. Each occurrence of the *
3763 * pattern causes a recursion level.
3764 */
3765static int match(char *name, char *pat, char *patend)
3766{
3767 int ok, negate_range;
3768 char c, k;
3769 char s1[6];
886e1ddb 3770
59241895
MJ
3771 while (pat < patend) {
3772 c = *pat++;
3773 switch (c & M_MASK) {
886e1ddb
AM
3774 case M_ALL:
3775 if (pat == patend)
3776 return (1);
3777 do
3778 if (match(name, pat, patend))
3779 return (1);
3780 while (*name++ != EOS);
3781 return (0);
3782 case M_ONE:
3783 if (*name++ == EOS)
3784 return (0);
3785 break;
3786 case M_SET:
3787 ok = 0;
3788 if ((k = *name++) == EOS)
3789 return (0);
3790 if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
3791 ++pat;
3792 while (((c = *pat++) & M_MASK) != M_END)
3793 if ((*pat & M_MASK) == M_RNG) {
3794 memset(s1, 0, sizeof(s1));
3795 s1[0] = c;
3796 s1[2] = k;
3797 s1[4] = pat[1];
3798 if (strcoll(&s1[0], &s1[2]) <= 0 && strcoll(&s1[2], &s1[4]) <= 0)
59241895 3799 ok = 1;
886e1ddb
AM
3800 pat += 2;
3801 } else if (c == k)
3802 ok = 1;
3803 if (ok == negate_range)
3804 return (0);
3805 break;
3806 default:
3807 if (*name++ != c)
3808 return (0);
3809 break;
59241895
MJ
3810 }
3811 }
886e1ddb 3812 return (*name == EOS);
59241895
MJ
3813}
3814
3815/* Free allocated data belonging to a glob_t structure. */
3816void globfree(glob_t *pglob)
3817{
5d4b5c3d 3818 size_t i;
59241895 3819 char **pp;
886e1ddb 3820
59241895
MJ
3821 if (pglob->gl_pathv != NULL) {
3822 pp = pglob->gl_pathv + pglob->gl_offs;
3823 for (i = pglob->gl_pathc; i--; ++pp)
3824 if (*pp)
3825 free(*pp);
3826 free(pglob->gl_pathv);
3827 pglob->gl_pathv = NULL;
3828 }
3829}
886e1ddb 3830
59241895
MJ
3831#pragma warning(pop)
3832#endif
3833
3834/* For Emacs:
3835 * Local Variables:
3836 * mode:c
3837 * indent-tabs-mode:t
3838 * tab-width:4
3839 * c-basic-offset:4
3840 * End:
3841 * For VIM:
32adc789 3842 * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet:
59241895 3843 */