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