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