From c1c759526d1ccf7cca8afcd139751133d382d34e Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Wed, 25 May 2011 15:42:36 -0500 Subject: [PATCH] add arrays to event headers and chanvars --- libs/esl/Makefile | 4 +- libs/esl/src/esl.c | 76 ++- libs/esl/src/esl_event.c | 502 ++++++++++++------ libs/esl/src/include/esl.h | 10 +- libs/esl/src/include/esl_event.h | 18 +- src/include/switch_channel.h | 6 +- src/include/switch_event.h | 12 +- src/include/switch_regex.h | 2 + src/include/switch_types.h | 5 +- .../applications/mod_dptools/mod_dptools.c | 31 +- .../mod_dialplan_xml/mod_dialplan_xml.c | 12 + src/mod/endpoints/mod_sofia/sofia_glue.c | 4 +- src/switch_channel.c | 45 +- src/switch_event.c | 353 ++++++++++-- src/switch_ivr.c | 38 +- src/switch_regex.c | 23 +- 16 files changed, 889 insertions(+), 252 deletions(-) diff --git a/libs/esl/Makefile b/libs/esl/Makefile index 7363304cdb..60bae27b5f 100644 --- a/libs/esl/Makefile +++ b/libs/esl/Makefile @@ -34,10 +34,10 @@ testclient: $(MYLIB) testclient.c fs_cli: $(MYLIB) fs_cli.c $(CC) $(CC_CFLAGS) $(CFLAGS) fs_cli.c -o fs_cli $(LDFLAGS) -L$(LIBEDIT_DIR)/src/.libs $(LIBS) -ledit -%.o: %.c +%.o: %.c $(HEADERS) $(CC) $(CC_CFLAGS) $(CFLAGS) -c $< -o $@ -%.o: %.cpp +%.o: %.cpp $(HEADERS) $(CXX) $(CXX_CFLAGS) $(CXXFLAGS) -c $< -o $@ clean: diff --git a/libs/esl/src/esl.c b/libs/esl/src/esl.c index bfdf58a625..675ecee460 100644 --- a/libs/esl/src/esl.c +++ b/libs/esl/src/esl.c @@ -1025,6 +1025,51 @@ static esl_ssize_t handle_recv(esl_handle_t *handle, void *data, esl_size_t data return recv(handle->sock, data, datalen, 0); } +static int add_array(esl_event_t *event, const char *var, const char *val) +{ + char *data; + char **array; + int idx; + int max = 0; + int len; + const char *p; + int i; + + if (strlen(val) < 8) { + return -1; + } + + p = val + 7; + + while((p = strstr(p, "::"))) { + max++; + p += 2; + } + + if (!max) { + return -2; + } + + data = strdup(val + 7); + + len = (sizeof(char *) * max) + 1; + array = malloc(len); + memset(array, 0, len); + + idx = esl_separate_string_string(data, "::", array, max); + + for(i = 0; i < max; i++) { + esl_event_add_header_string(event, ESL_STACK_PUSH, var, array[i]); + } + + free(array); + free(data); + + return 0; +} + + + ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_event_t **save_event) { char *c; @@ -1088,7 +1133,11 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ if (hname && hval) { esl_url_decode(hval); esl_log(ESL_LOG_DEBUG, "RECV HEADER [%s] = [%s]\n", hname, hval); - esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); + if (!strncmp(hval, "ARRAY::", 7)) { + add_array(revent, hname, hval); + } else { + esl_event_add_header_string(revent, ESL_STACK_BOTTOM, hname, hval); + } } p = e; @@ -1217,7 +1266,12 @@ ESL_DECLARE(esl_status_t) esl_recv_event(esl_handle_t *handle, int check_q, esl_ esl_event_del_header(handle->last_ievent, "event-name"); esl_name_event(hval, &handle->last_ievent->event_id); } - esl_event_add_header_string(handle->last_ievent, ESL_STACK_BOTTOM, hname, hval); + + if (!strncmp(hval, "ARRAY::", 7)) { + add_array(handle->last_ievent, hname, hval); + } else { + esl_event_add_header_string(handle->last_ievent, ESL_STACK_BOTTOM, hname, hval); + } } beg = c + 1; @@ -1371,5 +1425,23 @@ ESL_DECLARE(esl_status_t) esl_send_recv_timed(esl_handle_t *handle, const char * } +ESL_DECLARE(unsigned int) esl_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen) +{ + unsigned int count = 0; + char *d; + size_t dlen = strlen(delim); + array[count++] = buf; + + while (count < arraylen && array[count - 1]) { + if ((d = strstr(array[count - 1], delim))) { + *d = '\0'; + d += dlen; + array[count++] = d; + } else + break; + } + + return count; +} diff --git a/libs/esl/src/esl_event.c b/libs/esl/src/esl_event.c index 9bd78a838d..614d1b6190 100644 --- a/libs/esl/src/esl_event.c +++ b/libs/esl/src/esl_event.c @@ -235,8 +235,7 @@ static unsigned int esl_ci_hashfunc_default(const char *char_key, esl_ssize_t *k return hash; } - -ESL_DECLARE(char *)esl_event_get_header(esl_event_t *event, const char *header_name) +ESL_DECLARE(esl_event_header_t *) esl_event_get_header_ptr(esl_event_t *event, const char *header_name) { esl_event_header_t *hp; esl_ssize_t hlen = -1; @@ -244,18 +243,39 @@ ESL_DECLARE(char *)esl_event_get_header(esl_event_t *event, const char *header_n esl_assert(event); - if (!header_name) return NULL; - + if (!header_name) + return NULL; + hash = esl_ci_hashfunc_default(header_name, &hlen); - + for (hp = event->headers; hp; hp = hp->next) { - if ((!hp->hash || hash == hp->hash) && !strcasecmp(hp->name, header_name) ) { - return hp->value; + if ((!hp->hash || hash == hp->hash) && !strcasecmp(hp->name, header_name)) { + return hp; } } return NULL; } +ESL_DECLARE(char *) esl_event_get_header_idx(esl_event_t *event, const char *header_name, int idx) +{ + esl_event_header_t *hp; + + if ((hp = esl_event_get_header_ptr(event, header_name))) { + if (idx > -1) { + if (idx < hp->idx) { + return hp->array[idx]; + } else { + return NULL; + } + } + + return hp->value; + + } + + return NULL; +} + ESL_DECLARE(char *)esl_event_get_body(esl_event_t *event) { return (event ? event->body : NULL); @@ -264,7 +284,7 @@ ESL_DECLARE(char *)esl_event_get_body(esl_event_t *event) ESL_DECLARE(esl_status_t) esl_event_del_header_val(esl_event_t *event, const char *header_name, const char *val) { esl_event_header_t *hp, *lp = NULL, *tp; - esl_status_t status = ESL_FAIL; + esl_status_t status = ESL_FALSE; int x = 0; esl_ssize_t hlen = -1; unsigned long hash = 0; @@ -273,12 +293,12 @@ ESL_DECLARE(esl_status_t) esl_event_del_header_val(esl_event_t *event, const cha while (tp) { hp = tp; tp = tp->next; - + x++; - esl_assert(x < 1000); + esl_assert(x < 1000000); hash = esl_ci_hashfunc_default(header_name, &hlen); - if (hp->name && (!hp->hash || hash == hp->hash) && !strcasecmp(header_name, hp->name) && (esl_strlen_zero(val) || !strcmp(hp->value, val))) { + if ((!hp->hash || hash == hp->hash) && !strcasecmp(header_name, hp->name) && (esl_strlen_zero(val) || !strcmp(hp->value, val))) { if (lp) { lp->next = hp->next; } else { @@ -288,10 +308,27 @@ ESL_DECLARE(esl_status_t) esl_event_del_header_val(esl_event_t *event, const cha event->last_header = lp; } FREE(hp->name); - FREE(hp->value); - memset(hp, 0, sizeof(*hp)); - FREE(hp); + if (hp->idx) { + int i = 0; + hp->value = NULL; + + for (i = 0; i < hp->idx; i++) { + FREE(hp->array[i]); + } + FREE(hp->array); + } + + FREE(hp->value); + + memset(hp, 0, sizeof(*hp)); +#ifdef ESL_EVENT_RECYCLE + if (esl_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, hp) != ESL_SUCCESS) { + FREE(hp); + } +#else + FREE(hp); +#endif status = ESL_SUCCESS; } else { lp = hp; @@ -303,36 +340,122 @@ ESL_DECLARE(esl_status_t) esl_event_del_header_val(esl_event_t *event, const cha static esl_status_t esl_event_base_add_header(esl_event_t *event, esl_stack_t stack, const char *header_name, char *data) { - esl_event_header_t *header; + esl_event_header_t *header = NULL; esl_ssize_t hlen = -1; + int exists = 0; - header = ALLOC(sizeof(*header)); - esl_assert(header); + if ((stack & ESL_STACK_PUSH) || (stack & ESL_STACK_UNSHIFT) || esl_test_flag(event, ESL_EF_CONTAINS_ARRAYS)) { - if ((event->flags & ESL_UNIQ_HEADERS)) { - esl_event_del_header(event, header_name); + if ((header = esl_event_get_header_ptr(event, header_name))) { + + if (!(stack & ESL_STACK_PUSH) && !(stack & ESL_STACK_UNSHIFT) && header->idx) { + stack |= ESL_STACK_PUSH; + } + + if ((stack & ESL_STACK_PUSH) || (stack & ESL_STACK_UNSHIFT)) { + exists++; + stack &= ~(ESL_STACK_TOP | ESL_STACK_BOTTOM); + } else { + header = NULL; + } + } } - memset(header, 0, sizeof(*header)); + if (!header) { - header->name = DUP(header_name); - header->value = data; - header->hash = esl_ci_hashfunc_default(header->name, &hlen); +#ifdef ESL_EVENT_RECYCLE + void *pop; + if (esl_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE, &pop) == ESL_SUCCESS) { + header = (esl_event_header_t *) pop; + } else { +#endif + header = ALLOC(sizeof(*header)); + esl_assert(header); +#ifdef ESL_EVENT_RECYCLE + } +#endif - if (stack == ESL_STACK_TOP) { - header->next = event->headers; - event->headers = header; - if (!event->last_header) { + + if (esl_test_flag(event, ESL_EF_UNIQ_HEADERS)) { + esl_event_del_header(event, header_name); + } + + memset(header, 0, sizeof(*header)); + + header->name = DUP(header_name); + } + + if ((stack & ESL_STACK_PUSH) || (stack & ESL_STACK_UNSHIFT)) { + char **m = NULL; + esl_size_t len = 0; + char *hv; + int i = 0, j = 0; + + esl_set_flag(event, ESL_EF_CONTAINS_ARRAYS); + + if (header->value && !header->idx) { + m = malloc(sizeof(char *)); + esl_assert(m); + m[0] = header->value; + header->value = NULL; + header->array = m; + header->idx++; + m = NULL; + } + + i = header->idx + 1; + m = realloc(header->array, sizeof(char *) * i); + esl_assert(m); + + if ((stack & ESL_STACK_PUSH)) { + m[header->idx] = data; + } else if ((stack & ESL_STACK_UNSHIFT)) { + for (j = header->idx; j > 0; j--) { + m[j] = m[j-1]; + } + m[0] = data; + } + + header->idx++; + header->array = m; + + for(j = 0; j < header->idx; j++) { + len += strlen(header->array[j]) + 2; + } + + if (len) { + len += 8; + hv = realloc(header->value, len); + esl_assert(hv); + header->value = hv; + esl_snprintf(header->value, len, "ARRAY::"); + for(j = 0; j < header->idx; j++) { + esl_snprintf(header->value + strlen(header->value), len - strlen(header->value), "%s%s", j == 0 ? "" : "::", header->array[j]); + } + } + + } else { + header->value = data; + } + + if (!exists) { + header->hash = esl_ci_hashfunc_default(header->name, &hlen); + + if ((stack & ESL_STACK_TOP)) { + header->next = event->headers; + event->headers = header; + if (!event->last_header) { + event->last_header = header; + } + } else { + if (event->last_header) { + event->last_header->next = header; + } else { + event->headers = header; + header->next = NULL; + } event->last_header = header; } - } else { - if (event->last_header) { - event->last_header->next = header; - } else { - event->headers = header; - header->next = NULL; - } - event->last_header = header; } return ESL_SUCCESS; @@ -386,48 +509,98 @@ ESL_DECLARE(esl_status_t) esl_event_add_body(esl_event_t *event, const char *fmt } } + ESL_DECLARE(void) esl_event_destroy(esl_event_t **event) { - esl_event_t *ep = *event, *this_event; - esl_event_header_t *hp, *this_header; + esl_event_t *ep = *event; + esl_event_header_t *hp, *this; - for (ep = *event ; ep ;) { - this_event = ep; - ep = ep->next; - - for (hp = this_event->headers; hp;) { - this_header = hp; + if (ep) { + for (hp = ep->headers; hp;) { + this = hp; hp = hp->next; - FREE(this_header->name); - FREE(this_header->value); - memset(this_header, 0, sizeof(*this_header)); - FREE(this_header); + FREE(this->name); + + if (this->idx) { + int i = 0; + this->value = NULL; + for (i = 0; i < this->idx; i++) { + FREE(this->array[i]); + } + FREE(this->array); + } + + FREE(this->value); + + +#ifdef ESL_EVENT_RECYCLE + if (esl_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, this) != ESL_SUCCESS) { + FREE(this); + } +#else + FREE(this); +#endif + + } - FREE(this_event->body); - FREE(this_event->subclass_name); - memset(this_event, 0, sizeof(*this_event)); - FREE(this_event); + FREE(ep->body); + FREE(ep->subclass_name); +#ifdef ESL_EVENT_RECYCLE + if (esl_queue_trypush(EVENT_RECYCLE_QUEUE, ep) != ESL_SUCCESS) { + FREE(ep); + } +#else + FREE(ep); +#endif + } *event = NULL; } +ESL_DECLARE(void) esl_event_merge(esl_event_t *event, esl_event_t *tomerge) +{ + esl_event_header_t *hp; + + esl_assert(tomerge && event); + for (hp = tomerge->headers; hp; hp = hp->next) { + if (hp->idx) { + int i; + + for(i = 0; i < hp->idx; i++) { + esl_event_add_header_string(event, ESL_STACK_PUSH, hp->name, hp->array[i]); + } + } else { + esl_event_add_header_string(event, ESL_STACK_BOTTOM, hp->name, hp->value); + } + } +} ESL_DECLARE(esl_status_t) esl_event_dup(esl_event_t **event, esl_event_t *todup) { esl_event_header_t *hp; if (esl_event_create_subclass(event, ESL_EVENT_CLONE, todup->subclass_name) != ESL_SUCCESS) { - return ESL_FAIL; + return ESL_GENERR; } (*event)->event_id = todup->event_id; - (*event)->event_user_data = todup->event_user_data; (*event)->bind_user_data = todup->bind_user_data; - + (*event)->flags = todup->flags; for (hp = todup->headers; hp; hp = hp->next) { - esl_event_add_header_string(*event, ESL_STACK_BOTTOM, hp->name, hp->value); + if (todup->subclass_name && !strcmp(hp->name, "Event-Subclass")) { + continue; + } + + if (hp->idx) { + int i; + for (i = 0; i < hp->idx; i++) { + esl_event_add_header_string(*event, ESL_STACK_PUSH, hp->name, hp->array[i]); + } + } else { + esl_event_add_header_string(*event, ESL_STACK_BOTTOM, hp->name, hp->value); + } } if (todup->body) { @@ -439,97 +612,26 @@ ESL_DECLARE(esl_status_t) esl_event_dup(esl_event_t **event, esl_event_t *todup) return ESL_SUCCESS; } -ESL_DECLARE(esl_status_t) esl_event_create_json(esl_event_t **event, const char *json) -{ - esl_event_t *new_event; - cJSON *cj, *cjp; - - - if (!(cj = cJSON_Parse(json))) { - return ESL_FAIL; - } - - if (esl_event_create(&new_event, ESL_EVENT_CLONE) != ESL_SUCCESS) { - cJSON_Delete(cj); - return ESL_FAIL; - } - - for (cjp = cj->child; cjp; cjp = cjp->next) { - char *name = cjp->string; - char *value = cjp->valuestring; - - if (name && value) { - if (!strcasecmp(name, "_body")) { - esl_event_add_body(new_event, value); - } else { - if (!strcasecmp(name, "event-name")) { - esl_event_del_header(new_event, "event-name"); - } - - esl_name_event(value, &new_event->event_id); - esl_event_add_header_string(new_event, ESL_STACK_BOTTOM, name, value); - } - - } - } - - cJSON_Delete(cj); - *event = new_event; - return ESL_SUCCESS; -} - -ESL_DECLARE(esl_status_t) esl_event_serialize_json(esl_event_t *event, char **str) -{ - esl_event_header_t *hp; - cJSON *cj; - - *str = NULL; - - cj = cJSON_CreateObject(); - - for (hp = event->headers; hp; hp = hp->next) { - cJSON_AddItemToObject(cj, hp->name, cJSON_CreateString(hp->value)); - } - if (event->body) { - int blen = (int) strlen(event->body); - char tmp[25]; - - esl_snprintf(tmp, sizeof(tmp), "%d", blen); - - cJSON_AddItemToObject(cj, "Content-Length", cJSON_CreateString(tmp)); - cJSON_AddItemToObject(cj, "_body", cJSON_CreateString(event->body)); - } - - *str = cJSON_Print(cj); - cJSON_Delete(cj); - - return ESL_SUCCESS; -} ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, esl_bool_t encode) { - size_t len = 0; + esl_size_t len = 0; esl_event_header_t *hp; - size_t llen = 0, dlen = 0, blocksize = 512, encode_len = 1536, new_len = 0; + esl_size_t llen = 0, dlen = 0, blocksize = 512, encode_len = 1536, new_len = 0; char *buf; char *encode_buf = NULL; /* used for url encoding of variables to make sure unsafe things stay out of the serialized copy */ - int clen = 0; - - if (!event || !event->headers) - return ESL_FAIL; *str = NULL; dlen = blocksize * 2; if (!(buf = malloc(dlen))) { - return ESL_FAIL; + abort(); } /* go ahead and give ourselves some space to work with, should save a few reallocs */ if (!(encode_buf = malloc(encode_len))) { - esl_safe_free(buf); - return ESL_FAIL; + abort(); } /* esl_log_printf(ESL_CHANNEL_LOG, ESL_LOG_INFO, "hit serialized!.\n"); */ @@ -542,38 +644,39 @@ ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, es * destroying loop. */ - if (!strcasecmp(hp->name, "content-length")) { - clen++; + if (hp->idx) { + int i; + new_len = 0; + for(i = 0; i < hp->idx; i++) { + new_len += (strlen(hp->array[i]) * 3) + 1; + } + } else { + new_len = (strlen(hp->value) * 3) + 1; } - - new_len = (strlen(hp->value) * 3) + 1; - if (encode_len < new_len) { char *tmp; - /* esl_log_printf(ESL_CHANNEL_LOG, ESL_LOG_INFO, "Allocing %d was %d.\n", ((strlen(hp->value) * 3) + 1), encode_len); */ - /* we can use realloc for initial alloc as well, if encode_buf is zero it treats it as a malloc */ /* keep track of the size of our allocation */ encode_len = new_len; if (!(tmp = realloc(encode_buf, encode_len))) { - /* oh boy, ram's gone, give back what little we grabbed and bail */ - esl_safe_free(buf); - esl_safe_free(encode_buf); - return ESL_FAIL; + abort(); } encode_buf = tmp; } /* handle any bad things in the string like newlines : etc that screw up the serialized format */ + + if (encode) { esl_url_encode(hp->value, encode_buf, encode_len); } else { - esl_snprintf(encode_buf, encode_len, "%s", hp->value); + esl_snprintf(encode_buf, encode_len, "[%s]", hp->value); } + llen = strlen(hp->name) + strlen(encode_buf) + 8; if ((len + llen) > dlen) { @@ -582,14 +685,11 @@ ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, es if ((m = realloc(buf, dlen))) { buf = m; } else { - /* we seem to be out of memory trying to resize the serialize string, give back what we already have and give up */ - esl_safe_free(buf); - esl_safe_free(encode_buf); - return ESL_FAIL; + abort(); } } - snprintf(buf + len, dlen - len, "%s: %s\n", hp->name, *encode_buf == '\0' ? "_undef_" : encode_buf); + esl_snprintf(buf + len, dlen - len, "%s: %s\n", hp->name, *encode_buf == '\0' ? "_undef_" : encode_buf); len = strlen(buf); } @@ -612,29 +712,115 @@ ESL_DECLARE(esl_status_t) esl_event_serialize(esl_event_t *event, char **str, es if ((m = realloc(buf, dlen))) { buf = m; } else { - esl_safe_free(buf); - return ESL_FAIL; + abort(); } } - + if (blen) { - if (clen) { - snprintf(buf + len, dlen - len, "\n%s", event->body); - } else { - snprintf(buf + len, dlen - len, "Content-Length: %d\n\n%s", (int)strlen(event->body), event->body); - - } + esl_snprintf(buf + len, dlen - len, "Content-Length: %d\n\n%s", blen, event->body); + } else { + esl_snprintf(buf + len, dlen - len, "\n"); } } else { - snprintf(buf + len, dlen - len, "\n"); + esl_snprintf(buf + len, dlen - len, "\n"); } - *str = buf; return ESL_SUCCESS; } +ESL_DECLARE(esl_status_t) esl_event_create_json(esl_event_t **event, const char *json) +{ + esl_event_t *new_event; + cJSON *cj, *cjp; + + + if (!(cj = cJSON_Parse(json))) { + return ESL_FALSE; + } + + if (esl_event_create(&new_event, ESL_EVENT_CLONE) != ESL_SUCCESS) { + cJSON_Delete(cj); + return ESL_FALSE; + } + + for (cjp = cj->child; cjp; cjp = cjp->next) { + char *name = cjp->string; + char *value = cjp->valuestring; + + if (name && value) { + if (!strcasecmp(name, "_body")) { + esl_event_add_body(new_event, value, ESL_VA_NONE); + } else { + if (!strcasecmp(name, "event-name")) { + esl_event_del_header(new_event, "event-name"); + esl_name_event(value, &new_event->event_id); + } + + esl_event_add_header_string(new_event, ESL_STACK_BOTTOM, name, value); + } + + } else if (name) { + if (cjp->type == cJSON_Array) { + int i, x = cJSON_GetArraySize(cjp); + + for (i = 0; i < x; i++) { + cJSON *item = cJSON_GetArrayItem(cjp, i); + + if (item && item->type == cJSON_String && item->valuestring) { + esl_event_add_header_string(new_event, ESL_STACK_PUSH, name, item->valuestring); + } + } + } + } + } + + cJSON_Delete(cj); + *event = new_event; + return ESL_SUCCESS; +} + +ESL_DECLARE(esl_status_t) esl_event_serialize_json(esl_event_t *event, char **str) +{ + esl_event_header_t *hp; + cJSON *cj; + + *str = NULL; + + cj = cJSON_CreateObject(); + + for (hp = event->headers; hp; hp = hp->next) { + if (hp->idx) { + cJSON *a = cJSON_CreateArray(); + int i; + + for(i = 0; i < hp->idx; i++) { + cJSON_AddItemToArray(a, cJSON_CreateString(hp->array[i])); + } + + cJSON_AddItemToObject(cj, hp->name, a); + + } else { + cJSON_AddItemToObject(cj, hp->name, cJSON_CreateString(hp->value)); + } + } + + if (event->body) { + int blen = (int) strlen(event->body); + char tmp[25]; + + esl_snprintf(tmp, sizeof(tmp), "%d", blen); + + cJSON_AddItemToObject(cj, "Content-Length", cJSON_CreateString(tmp)); + cJSON_AddItemToObject(cj, "_body", cJSON_CreateString(event->body)); + } + + *str = cJSON_Print(cj); + cJSON_Delete(cj); + + return ESL_SUCCESS; +} /* For Emacs: * Local Variables: diff --git a/libs/esl/src/include/esl.h b/libs/esl/src/include/esl.h index 17ebf26ee1..095e814a0e 100644 --- a/libs/esl/src/include/esl.h +++ b/libs/esl/src/include/esl.h @@ -42,6 +42,7 @@ extern "C" { #define esl_copy_string(_x, _y, _z) strncpy(_x, _y, _z - 1) #define esl_set_string(_x, _y) esl_copy_string(_x, _y, sizeof(_x)) +#define ESL_VA_NONE "%s", "" typedef struct esl_event_header esl_event_header_t; typedef struct esl_event esl_event_t; @@ -262,7 +263,8 @@ typedef enum { ESL_SUCCESS, ESL_FAIL, ESL_BREAK, - ESL_DISCONNECTED + ESL_DISCONNECTED, + ESL_GENERR } esl_status_t; #define BUF_CHUNK 65536 * 50 @@ -309,6 +311,10 @@ typedef struct { int destroyed; } esl_handle_t; +#define esl_test_flag(obj, flag) ((obj)->flags & flag) +#define esl_set_flag(obj, flag) (obj)->flags |= (flag) +#define esl_clear_flag(obj, flag) (obj)->flags &= ~(flag) + /*! \brief Used internally for truth test */ typedef enum { ESL_TRUE = 1, @@ -453,6 +459,8 @@ ESL_DECLARE(esl_status_t) esl_events(esl_handle_t *handle, esl_event_type_t etyp ESL_DECLARE(int) esl_wait_sock(esl_socket_t sock, uint32_t ms, esl_poll_t flags); +ESL_DECLARE(unsigned int) esl_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen); + #define esl_recv(_h) esl_recv_event(_h, 0, NULL) #define esl_recv_timed(_h, _ms) esl_recv_event_timed(_h, _ms, 0, NULL) diff --git a/libs/esl/src/include/esl_event.h b/libs/esl/src/include/esl_event.h index 7e619f4764..10af7264b9 100644 --- a/libs/esl/src/include/esl_event.h +++ b/libs/esl/src/include/esl_event.h @@ -42,7 +42,9 @@ extern "C" { typedef enum { ESL_STACK_BOTTOM, - ESL_STACK_TOP + ESL_STACK_TOP, + ESL_STACK_PUSH, + ESL_STACK_UNSHIFT } esl_stack_t; typedef enum { @@ -141,6 +143,10 @@ typedef enum { char *name; /*! the header value */ char *value; + /*! array space */ + char **array; + /*! array index */ + int idx; /*! hash of the header name */ unsigned long hash; struct esl_event_header *next; @@ -174,7 +180,8 @@ struct esl_event { }; typedef enum { - ESL_UNIQ_HEADERS = (1 << 0) + ESL_EF_UNIQ_HEADERS = (1 << 0), + ESL_EF_CONTAINS_ARRAYS = (1 << 1) } esl_event_flag_t; @@ -203,7 +210,11 @@ ESL_DECLARE(esl_status_t) esl_event_set_priority(esl_event_t *event, esl_priorit \param header_name the name of the header to read \return the value of the requested header */ -ESL_DECLARE(char *)esl_event_get_header(esl_event_t *event, const char *header_name); + + +ESL_DECLARE(esl_event_header_t *) esl_event_get_header_ptr(esl_event_t *event, const char *header_name); +ESL_DECLARE(char *) esl_event_get_header_idx(esl_event_t *event, const char *header_name, int idx); +#define esl_event_get_header(_e, _h) esl_event_get_header_idx(_e, _h, -1) /*! \brief Retrieve the body value from an event @@ -250,6 +261,7 @@ ESL_DECLARE(void) esl_event_destroy(esl_event_t **event); \return ESL_SUCCESS if the event was duplicated */ ESL_DECLARE(esl_status_t) esl_event_dup(esl_event_t **event, esl_event_t *todup); +ESL_DECLARE(void) esl_event_merge(esl_event_t *event, esl_event_t *tomerge); /*! \brief Render the name of an event id enumeration diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index dc8175b202..40d4ee6b13 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -251,6 +251,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check); +SWITCH_DECLARE(switch_status_t) switch_channel_add_variable_var_check(switch_channel_t *channel, + const char *varname, const char *value, switch_bool_t var_check, switch_stack_t stack); SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_printf(switch_channel_t *channel, const char *varname, const char *fmt, ...); SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_name_printf(switch_channel_t *channel, const char *val, const char *fmt, ...); @@ -284,8 +286,8 @@ SWITCH_DECLARE(switch_status_t) switch_channel_export_variable_printf(switch_cha \param varname the name of the variable \return the value of the requested variable */ -SWITCH_DECLARE(const char *) switch_channel_get_variable_dup(switch_channel_t *channel, const char *varname, switch_bool_t dup); -#define switch_channel_get_variable(_c, _v) switch_channel_get_variable_dup(_c, _v, SWITCH_TRUE) +SWITCH_DECLARE(const char *) switch_channel_get_variable_dup(switch_channel_t *channel, const char *varname, switch_bool_t dup, int idx); +#define switch_channel_get_variable(_c, _v) switch_channel_get_variable_dup(_c, _v, SWITCH_TRUE, -1) SWITCH_DECLARE(switch_status_t) switch_channel_get_variables(switch_channel_t *channel, switch_event_t **event); diff --git a/src/include/switch_event.h b/src/include/switch_event.h index 9046bc711a..642e39afeb 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -67,6 +67,10 @@ SWITCH_BEGIN_EXTERN_C char *name; /*! the header value */ char *value; + /*! array space */ + char **array; + /*! array index */ + int idx; /*! hash of the header name */ unsigned long hash; struct switch_event_header *next; @@ -99,7 +103,8 @@ struct switch_event { }; typedef enum { - EF_UNIQ_HEADERS = (1 << 0) + EF_UNIQ_HEADERS = (1 << 0), + EF_CONTAINS_ARRAYS = (1 << 1), } switch_event_flag_t; @@ -146,7 +151,10 @@ SWITCH_DECLARE(switch_status_t) switch_event_set_priority(switch_event_t *event, \param header_name the name of the header to read \return the value of the requested header */ - _Ret_opt_z_ SWITCH_DECLARE(char *) switch_event_get_header(switch_event_t *event, const char *header_name); + +_Ret_opt_z_ SWITCH_DECLARE(switch_event_header_t *) switch_event_get_header_ptr(switch_event_t *event, const char *header_name); +_Ret_opt_z_ SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t *event, const char *header_name, int idx); +#define switch_event_get_header(_e, _h) switch_event_get_header_idx(_e, _h, -1) #define switch_event_get_header_nil(e, h) switch_str_nil(switch_event_get_header(e,h)) diff --git a/src/include/switch_regex.h b/src/include/switch_regex.h index 96d623043c..4c5f14961f 100644 --- a/src/include/switch_regex.h +++ b/src/include/switch_regex.h @@ -70,6 +70,8 @@ SWITCH_DECLARE(switch_status_t) switch_regex_match(const char *target, const cha */ SWITCH_DECLARE(switch_status_t) switch_regex_match_partial(const char *target, const char *expression, int *partial_match); +SWITCH_DECLARE(void) switch_capture_regex(switch_regex_t *re, int match_count, const char *field_data, + int *ovector, const char *var, switch_cap_callback_t callback, void *user_data); #define switch_regex_safe_free(re) if (re) {\ switch_regex_free(re);\ diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 6664dc0653..2b2b3de45d 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -830,7 +830,9 @@ SWITCH_STACK_TOP - Stack on the top typedef enum { SWITCH_STACK_BOTTOM = (1 << 0), SWITCH_STACK_TOP = (1 << 1), - SWITCH_STACK_NODUP = (1 << 2) + SWITCH_STACK_NODUP = (1 << 2), + SWITCH_STACK_UNSHIFT = (1 << 3), + SWITCH_STACK_PUSH = (1 << 4), } switch_stack_t; /*! @@ -1688,6 +1690,7 @@ struct switch_console_callback_match { }; typedef struct switch_console_callback_match switch_console_callback_match_t; +typedef void (*switch_cap_callback_t) (const char *var, const char *val, void *user_data); typedef switch_status_t (*switch_console_complete_callback_t) (const char *, const char *, switch_console_callback_match_t **matches); typedef switch_bool_t (*switch_media_bug_callback_t) (switch_media_bug_t *, void *, switch_abc_type_t); typedef switch_bool_t (*switch_tone_detect_callback_t) (switch_core_session_t *, const char *, const char *); diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 5b982111d5..88bcaf86b6 100755 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -1033,7 +1033,7 @@ SWITCH_STANDARD_APP(sched_cancel_function) switch_scheduler_del_task_group(group); } -SWITCH_STANDARD_APP(set_function) +static void base_set (switch_core_session_t *session, const char *data, switch_stack_t stack) { char *var, *val = NULL; @@ -1044,7 +1044,10 @@ SWITCH_STANDARD_APP(set_function) char *expanded = NULL; var = switch_core_session_strdup(session, data); - val = strchr(var, '='); + + if (!(val = strchr(var, '='))) { + val = strchr(var, ','); + } if (val) { *val++ = '\0'; @@ -1059,7 +1062,7 @@ SWITCH_STANDARD_APP(set_function) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SET [%s]=[%s]\n", switch_channel_get_name(channel), var, expanded ? expanded : "UNDEF"); - switch_channel_set_variable_var_check(channel, var, expanded, SWITCH_FALSE); + switch_channel_add_variable_var_check(channel, var, expanded, SWITCH_FALSE, stack); if (expanded && expanded != val) { switch_safe_free(expanded); @@ -1067,6 +1070,21 @@ SWITCH_STANDARD_APP(set_function) } } +SWITCH_STANDARD_APP(set_function) +{ + base_set(session, data, SWITCH_STACK_BOTTOM); +} + +SWITCH_STANDARD_APP(push_function) +{ + base_set(session, data, SWITCH_STACK_PUSH); +} + +SWITCH_STANDARD_APP(unshift_function) +{ + base_set(session, data, SWITCH_STACK_UNSHIFT); +} + SWITCH_STANDARD_APP(set_global_function) { char *var, *val = NULL; @@ -3769,6 +3787,13 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); SWITCH_ADD_APP(app_interface, "set", "Set a channel variable", SET_LONG_DESC, set_function, "=", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); + + SWITCH_ADD_APP(app_interface, "push", "Set a channel variable", SET_LONG_DESC, push_function, "=", + SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); + + SWITCH_ADD_APP(app_interface, "unshift", "Set a channel variable", SET_LONG_DESC, unshift_function, "=", + SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); + SWITCH_ADD_APP(app_interface, "set_global", "Set a global variable", SET_GLOBAL_LONG_DESC, set_global_function, "=", SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC); SWITCH_ADD_APP(app_interface, "set_profile_var", "Set a caller profile variable", SET_PROFILE_VAR_LONG_DESC, set_profile_var_function, diff --git a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c index 929372be1a..3b5f6995e4 100644 --- a/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c +++ b/src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c @@ -79,6 +79,13 @@ static switch_status_t exec_app(switch_core_session_t *session, const char *app, return status; } +static void set_var_callback(const char *var, const char *val, void *user_data) +{ + switch_core_session_t *session = (switch_core_session_t *) user_data; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_add_variable_var_check(channel, var, val, SWITCH_FALSE, SWITCH_STACK_PUSH); +} + static int parse_exten(switch_core_session_t *session, switch_caller_profile_t *caller_profile, switch_xml_t xexten, switch_caller_extension_t **extension) { switch_xml_t xcond, xaction, xexpression; @@ -222,6 +229,11 @@ static int parse_exten(switch_core_session_t *session, switch_caller_profile_t * proceed = 1; } } else { + if (field && strchr(expression, '(')) { + switch_channel_set_variable(channel, "DP_MATCH", NULL); + switch_capture_regex(re, proceed, field_data, ovector, "DP_MATCH", set_var_callback, session); + } + for (xaction = switch_xml_child(xcond, "action"); xaction; xaction = xaction->next) { char *application = (char *) switch_xml_attr_soft(xaction, "application"); const char *loop = switch_xml_attr(xaction, "loop"); diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index 2724e5e562..8af77a17d7 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -5332,11 +5332,11 @@ static int recover_callback(void *pArg, int argc, char **argv, char **columnName tech_pvt->dest = switch_core_session_sprintf(session, "sip:%s", switch_channel_get_variable(channel, "sip_from_uri")); - if (!switch_channel_get_variable_dup(channel, "sip_handle_full_from", SWITCH_FALSE)) { + if (!switch_channel_get_variable_dup(channel, "sip_handle_full_from", SWITCH_FALSE, -1)) { switch_channel_set_variable(channel, "sip_handle_full_from", switch_channel_get_variable(channel, "sip_full_to")); } - if (!switch_channel_get_variable_dup(channel, "sip_handle_full_to", SWITCH_FALSE)) { + if (!switch_channel_get_variable_dup(channel, "sip_handle_full_to", SWITCH_FALSE, -1)) { switch_channel_set_variable(channel, "sip_handle_full_to", switch_channel_get_variable(channel, "sip_full_from")); } } diff --git a/src/switch_channel.c b/src/switch_channel.c index 76538bdaa6..d31b75e478 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -675,13 +675,13 @@ SWITCH_DECLARE(const char *) switch_channel_get_hold_music_partner(switch_channe return r; } -SWITCH_DECLARE(const char *) switch_channel_get_variable_dup(switch_channel_t *channel, const char *varname, switch_bool_t dup) +SWITCH_DECLARE(const char *) switch_channel_get_variable_dup(switch_channel_t *channel, const char *varname, switch_bool_t dup, int idx) { const char *v = NULL, *r = NULL, *vdup = NULL; switch_assert(channel != NULL); switch_mutex_lock(channel->profile_mutex); - if (!channel->variables || !(v = switch_event_get_header(channel->variables, varname))) { + if (!channel->variables || !(v = switch_event_get_header_idx(channel->variables, varname, idx))) { switch_caller_profile_t *cp = channel->caller_profile; if (cp) { @@ -1032,8 +1032,6 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_cha switch_mutex_lock(channel->profile_mutex); if (channel->variables && !zstr(varname)) { - - switch_event_del_header(channel->variables, varname); if (!zstr(value)) { int ok = 1; @@ -1053,6 +1051,36 @@ SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_cha return status; } + +SWITCH_DECLARE(switch_status_t) switch_channel_add_variable_var_check(switch_channel_t *channel, + const char *varname, const char *value, switch_bool_t var_check, switch_stack_t stack) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + + switch_assert(channel != NULL); + + switch_mutex_lock(channel->profile_mutex); + if (channel->variables && !zstr(varname)) { + if (!zstr(value)) { + int ok = 1; + + if (var_check) { + ok = !switch_string_var_check_const(value); + } + if (ok) { + switch_event_add_header_string(channel->variables, stack, varname, value); + } else { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_CRIT, "Invalid data (${%s} contains a variable)\n", varname); + } + } + status = SWITCH_STATUS_SUCCESS; + } + switch_mutex_unlock(channel->profile_mutex); + + return status; +} + + switch_status_t switch_event_base_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, char *data); SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_printf(switch_channel_t *channel, const char *varname, const char *fmt, ...) @@ -3108,12 +3136,14 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel int offset = 0; int ooffset = 0; char *ptr; + int idx = -1; if ((expanded = switch_channel_expand_variables(channel, (char *) vname)) == vname) { expanded = NULL; } else { vname = expanded; } + if ((ptr = strchr(vname, ':'))) { *ptr++ = '\0'; offset = atoi(ptr); @@ -3123,7 +3153,12 @@ SWITCH_DECLARE(char *) switch_channel_expand_variables(switch_channel_t *channel } } - if ((sub_val = (char *) switch_channel_get_variable(channel, vname))) { + if ((ptr = strchr(vname, '[')) && strchr(ptr, ']')) { + *ptr++ = '\0'; + idx = atoi(ptr); + } + + if ((sub_val = (char *) switch_channel_get_variable_dup(channel, vname, SWITCH_TRUE, idx))) { if (offset || ooffset) { cloned_sub_val = strdup(sub_val); switch_assert(cloned_sub_val); diff --git a/src/switch_event.c b/src/switch_event.c index 6d97041901..0d5b3c3665 100644 --- a/src/switch_event.c +++ b/src/switch_event.c @@ -727,7 +727,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_set_priority(switch_event_t *event, return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(char *) switch_event_get_header(switch_event_t *event, const char *header_name) +SWITCH_DECLARE(switch_event_header_t *) switch_event_get_header_ptr(switch_event_t *event, const char *header_name) { switch_event_header_t *hp; switch_ssize_t hlen = -1; @@ -742,12 +742,31 @@ SWITCH_DECLARE(char *) switch_event_get_header(switch_event_t *event, const char for (hp = event->headers; hp; hp = hp->next) { if ((!hp->hash || hash == hp->hash) && !strcasecmp(hp->name, header_name)) { - return hp->value; + return hp; } } return NULL; } +SWITCH_DECLARE(char *) switch_event_get_header_idx(switch_event_t *event, const char *header_name, int idx) +{ + switch_event_header_t *hp; + + if ((hp = switch_event_get_header_ptr(event, header_name))) { + if (idx > -1) { + if (idx < hp->idx) { + return hp->array[idx]; + } else { + return NULL; + } + } + + return hp->value; + } + + return NULL; +} + SWITCH_DECLARE(char *) switch_event_get_body(switch_event_t *event) { return (event ? event->body : NULL); @@ -780,7 +799,19 @@ SWITCH_DECLARE(switch_status_t) switch_event_del_header_val(switch_event_t *even event->last_header = lp; } FREE(hp->name); + + if (hp->idx) { + int i = 0; + hp->value = NULL; + + for (i = 0; i < hp->idx; i++) { + FREE(hp->array[i]); + } + FREE(hp->array); + } + FREE(hp->value); + memset(hp, 0, sizeof(*hp)); #ifdef SWITCH_EVENT_RECYCLE if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, hp) != SWITCH_STATUS_SUCCESS) { @@ -798,49 +829,185 @@ SWITCH_DECLARE(switch_status_t) switch_event_del_header_val(switch_event_t *even return status; } -switch_status_t switch_event_base_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, char *data) +static switch_status_t switch_event_base_add_header(switch_event_t *event, switch_stack_t stack, const char *header_name, char *data) { - switch_event_header_t *header; + switch_event_header_t *header = NULL; switch_ssize_t hlen = -1; + int exists = 0, fly = 0; + char *index_ptr; + int index = 0; + char *real_header_name = NULL; + + if ((index_ptr = strchr(header_name, '['))) { + index_ptr++; + index = atoi(index_ptr); + real_header_name = DUP(header_name); + if ((index_ptr = strchr(real_header_name, '['))) { + *index_ptr++ = '\0'; + } + header_name = real_header_name; + } + + if (index_ptr || (stack & SWITCH_STACK_PUSH) || (stack & SWITCH_STACK_UNSHIFT) || switch_test_flag(event, EF_CONTAINS_ARRAYS)) { + + if (!(header = switch_event_get_header_ptr(event, header_name)) && index_ptr) { + header = ALLOC(sizeof(*header)); + switch_assert(header); + memset(header, 0, sizeof(*header)); + header->name = DUP(header_name); + if (switch_test_flag(event, EF_UNIQ_HEADERS)) { + switch_event_del_header(event, header_name); + } + fly++; + } + + if ((header = switch_event_get_header_ptr(event, header_name))) { + + if (index_ptr) { + if (index > -1 && index <= 4000) { + if (index < header->idx) { + FREE(header->array[index]); + header->array[index] = DUP(data); + } else { + int i; + char **m; + + m = realloc(header->array, sizeof(char *) * (index + 1)); + switch_assert(m); + header->array = m; + for (i = header->idx; i < index; i++) { + m[i] = DUP(""); + } + m[index] = DUP(data); + header->idx = index + 1; + if (!fly) { + exists = 1; + } + + goto redraw; + } + } + goto end; + } else { + + if (!(stack & SWITCH_STACK_PUSH) && !(stack & SWITCH_STACK_UNSHIFT) && header->idx) { + stack |= SWITCH_STACK_PUSH; + } + + if ((stack & SWITCH_STACK_PUSH) || (stack & SWITCH_STACK_UNSHIFT)) { + exists++; + stack &= ~(SWITCH_STACK_TOP | SWITCH_STACK_BOTTOM); + } else { + header = NULL; + } + } + } + } + + if (!header) { #ifdef SWITCH_EVENT_RECYCLE - void *pop; - if (switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE, &pop) == SWITCH_STATUS_SUCCESS) { - header = (switch_event_header_t *) pop; + void *pop; + if (switch_queue_trypop(EVENT_HEADER_RECYCLE_QUEUE, &pop) == SWITCH_STATUS_SUCCESS) { + header = (switch_event_header_t *) pop; + } else { +#endif + header = ALLOC(sizeof(*header)); + switch_assert(header); +#ifdef SWITCH_EVENT_RECYCLE + } +#endif + + + if (switch_test_flag(event, EF_UNIQ_HEADERS)) { + switch_event_del_header(event, header_name); + } + + memset(header, 0, sizeof(*header)); + + header->name = DUP(header_name); + } + + if ((stack & SWITCH_STACK_PUSH) || (stack & SWITCH_STACK_UNSHIFT)) { + char **m = NULL; + switch_size_t len = 0; + char *hv; + int i = 0, j = 0; + + switch_set_flag(event, EF_CONTAINS_ARRAYS); + + if (header->value && !header->idx) { + m = malloc(sizeof(char *)); + switch_assert(m); + m[0] = header->value; + header->value = NULL; + header->array = m; + header->idx++; + m = NULL; + } + + i = header->idx + 1; + m = realloc(header->array, sizeof(char *) * i); + switch_assert(m); + + if ((stack & SWITCH_STACK_PUSH)) { + m[header->idx] = data; + } else if ((stack & SWITCH_STACK_UNSHIFT)) { + for (j = header->idx; j > 0; j--) { + m[j] = m[j-1]; + } + m[0] = data; + } + + header->idx++; + header->array = m; + + redraw: + + for(j = 0; j < header->idx; j++) { + len += strlen(header->array[j]) + 2; + } + + if (len) { + len += 8; + hv = realloc(header->value, len); + switch_assert(hv); + header->value = hv; + + switch_snprintf(header->value, len, "ARRAY::"); + for(j = 0; j < header->idx; j++) { + switch_snprintf(header->value + strlen(header->value), len - strlen(header->value), "%s%s", j == 0 ? "" : "::", header->array[j]); + } + } + } else { -#endif - header = ALLOC(sizeof(*header)); - switch_assert(header); -#ifdef SWITCH_EVENT_RECYCLE - } -#endif - - if (switch_test_flag(event, EF_UNIQ_HEADERS)) { - switch_event_del_header(event, header_name); + header->value = data; } - memset(header, 0, sizeof(*header)); + if (!exists) { + header->hash = switch_ci_hashfunc_default(header->name, &hlen); - header->name = DUP(header_name); - header->value = data; - header->hash = switch_ci_hashfunc_default(header->name, &hlen); - - if ((stack & SWITCH_STACK_TOP)) { - header->next = event->headers; - event->headers = header; - if (!event->last_header) { + if ((stack & SWITCH_STACK_TOP)) { + header->next = event->headers; + event->headers = header; + if (!event->last_header) { + event->last_header = header; + } + } else { + if (event->last_header) { + event->last_header->next = header; + } else { + event->headers = header; + header->next = NULL; + } event->last_header = header; } - } else { - if (event->last_header) { - event->last_header->next = header; - } else { - event->headers = header; - header->next = NULL; - } - event->last_header = header; } + end: + + switch_safe_free(real_header_name); + return SWITCH_STATUS_SUCCESS; } @@ -914,7 +1081,19 @@ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event) this = hp; hp = hp->next; FREE(this->name); + + if (this->idx) { + int i = 0; + this->value = NULL; + for (i = 0; i < this->idx; i++) { + FREE(this->array[i]); + } + FREE(this->array); + } + FREE(this->value); + + #ifdef SWITCH_EVENT_RECYCLE if (switch_queue_trypush(EVENT_HEADER_RECYCLE_QUEUE, this) != SWITCH_STATUS_SUCCESS) { FREE(this); @@ -947,7 +1126,15 @@ SWITCH_DECLARE(void) switch_event_merge(switch_event_t *event, switch_event_t *t switch_assert(tomerge && event); for (hp = tomerge->headers; hp; hp = hp->next) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, hp->name, hp->value); + if (hp->idx) { + int i; + + for(i = 0; i < hp->idx; i++) { + switch_event_add_header_string(event, SWITCH_STACK_PUSH, hp->name, hp->array[i]); + } + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, hp->name, hp->value); + } } } @@ -967,7 +1154,15 @@ SWITCH_DECLARE(switch_status_t) switch_event_dup(switch_event_t **event, switch_ if (todup->subclass_name && !strcmp(hp->name, "Event-Subclass")) { continue; } - switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, hp->name, hp->value); + + if (hp->idx) { + int i; + for (i = 0; i < hp->idx; i++) { + switch_event_add_header_string(*event, SWITCH_STACK_PUSH, hp->name, hp->array[i]); + } + } else { + switch_event_add_header_string(*event, SWITCH_STACK_BOTTOM, hp->name, hp->value); + } } if (todup->body) { @@ -992,13 +1187,12 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, ch dlen = blocksize * 2; if (!(buf = malloc(dlen))) { - return SWITCH_STATUS_MEMERR; + abort(); } /* go ahead and give ourselves some space to work with, should save a few reallocs */ if (!(encode_buf = malloc(encode_len))) { - switch_safe_free(buf); - return SWITCH_STATUS_MEMERR; + abort(); } /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "hit serialized!.\n"); */ @@ -1011,33 +1205,39 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, ch * destroying loop. */ - new_len = (strlen(hp->value) * 3) + 1; + if (hp->idx) { + int i; + new_len = 0; + for(i = 0; i < hp->idx; i++) { + new_len += (strlen(hp->array[i]) * 3) + 1; + } + } else { + new_len = (strlen(hp->value) * 3) + 1; + } if (encode_len < new_len) { char *tmp; - /* switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Allocing %d was %d.\n", ((strlen(hp->value) * 3) + 1), encode_len); */ - /* we can use realloc for initial alloc as well, if encode_buf is zero it treats it as a malloc */ /* keep track of the size of our allocation */ encode_len = new_len; if (!(tmp = realloc(encode_buf, encode_len))) { - /* oh boy, ram's gone, give back what little we grabbed and bail */ - switch_safe_free(buf); - switch_safe_free(encode_buf); - return SWITCH_STATUS_MEMERR; + abort(); } encode_buf = tmp; } /* handle any bad things in the string like newlines : etc that screw up the serialized format */ + + if (encode) { switch_url_encode(hp->value, encode_buf, encode_len); } else { switch_snprintf(encode_buf, encode_len, "[%s]", hp->value); } + llen = strlen(hp->name) + strlen(encode_buf) + 8; if ((len + llen) > dlen) { @@ -1046,10 +1246,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, ch if ((m = realloc(buf, dlen))) { buf = m; } else { - /* we seem to be out of memory trying to resize the serialize string, give back what we already have and give up */ - switch_safe_free(buf); - switch_safe_free(encode_buf); - return SWITCH_STATUS_MEMERR; + abort(); } } @@ -1076,8 +1273,7 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize(switch_event_t *event, ch if ((m = realloc(buf, dlen))) { buf = m; } else { - switch_safe_free(buf); - return SWITCH_STATUS_MEMERR; + abort(); } } @@ -1212,19 +1408,31 @@ SWITCH_DECLARE(switch_status_t) switch_event_create_json(switch_event_t **event, for (cjp = cj->child; cjp; cjp = cjp->next) { char *name = cjp->string; char *value = cjp->valuestring; - + if (name && value) { if (!strcasecmp(name, "_body")) { switch_event_add_body(new_event, value, SWITCH_VA_NONE); } else { if (!strcasecmp(name, "event-name")) { switch_event_del_header(new_event, "event-name"); + switch_name_event(value, &new_event->event_id); } - - switch_name_event(value, &new_event->event_id); + switch_event_add_header_string(new_event, SWITCH_STACK_BOTTOM, name, value); } + } else if (name) { + if (cjp->type == cJSON_Array) { + int i, x = cJSON_GetArraySize(cjp); + + for (i = 0; i < x; i++) { + cJSON *item = cJSON_GetArrayItem(cjp, i); + + if (item && item->type == cJSON_String && item->valuestring) { + switch_event_add_header_string(new_event, SWITCH_STACK_PUSH, name, item->valuestring); + } + } + } } } @@ -1243,8 +1451,21 @@ SWITCH_DECLARE(switch_status_t) switch_event_serialize_json(switch_event_t *even cj = cJSON_CreateObject(); for (hp = event->headers; hp; hp = hp->next) { - cJSON_AddItemToObject(cj, hp->name, cJSON_CreateString(hp->value)); - } + if (hp->idx) { + cJSON *a = cJSON_CreateArray(); + int i; + + for(i = 0; i < hp->idx; i++) { + cJSON_AddItemToArray(a, cJSON_CreateString(hp->array[i])); + } + + cJSON_AddItemToObject(cj, hp->name, a); + + } else { + cJSON_AddItemToObject(cj, hp->name, cJSON_CreateString(hp->value)); + } + } + if (event->body) { int blen = (int) strlen(event->body); char tmp[25]; @@ -1316,7 +1537,15 @@ SWITCH_DECLARE(switch_xml_t) switch_event_xmlize(switch_event_t *event, const ch if ((xheaders = switch_xml_add_child_d(xml, "headers", off++))) { int hoff = 0; for (hp = event->headers; hp; hp = hp->next) { - add_xml_header(xheaders, hp->name, hp->value, hoff++); + + if (hp->idx) { + int i; + for (i = 0; i < hp->idx; i++) { + add_xml_header(xheaders, hp->name, hp->array[i], hoff++); + } + } else { + add_xml_header(xheaders, hp->name, hp->value, hoff++); + } } } @@ -1730,7 +1959,8 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const int offset = 0; int ooffset = 0; char *ptr; - + int idx = -1; + if ((expanded = switch_event_expand_headers(event, (char *) vname)) == vname) { expanded = NULL; } else { @@ -1745,7 +1975,12 @@ SWITCH_DECLARE(char *) switch_event_expand_headers(switch_event_t *event, const } } - if (!(sub_val = switch_event_get_header(event, vname))) { + if ((ptr = strchr(vname, '[')) && strchr(ptr, ']')) { + *ptr++ = '\0'; + idx = atoi(ptr); + } + + if (!(sub_val = switch_event_get_header_idx(event, vname, idx))) { switch_safe_free(gvar); if ((gvar = switch_core_get_variable_dup(vname))) { sub_val = gvar; diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 74c8f7efd0..5ab9f440c7 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -1982,25 +1982,43 @@ SWITCH_DECLARE(int) switch_ivr_set_xml_profile_data(switch_xml_t xml, switch_cal return off; } +static int switch_ivr_set_xml_chan_var(switch_xml_t xml, const char *var, const char *val, int off) +{ + char *data; + switch_size_t dlen = strlen(val) * 3 + 1; + switch_xml_t variable; + + if (!zstr(var) && !zstr(val) && ((variable = switch_xml_add_child_d(xml, var, off++)))) { + if ((data = malloc(dlen))) { + memset(data, 0, dlen); + switch_url_encode(val, data, dlen); + switch_xml_set_txt_d(variable, data); + free(data); + } else abort(); + } + + return off; + +} + + SWITCH_DECLARE(int) switch_ivr_set_xml_chan_vars(switch_xml_t xml, switch_channel_t *channel, int off) { - switch_xml_t variable; + switch_event_header_t *hi = switch_channel_variable_first(channel); if (!hi) return off; for (; hi; hi = hi->next) { - if (!zstr(hi->name) && !zstr(hi->value) && ((variable = switch_xml_add_child_d(xml, hi->name, off++)))) { - char *data; - switch_size_t dlen = strlen(hi->value) * 3 + 1; - - if ((data = malloc(dlen))) { - memset(data, 0, dlen); - switch_url_encode(hi->value, data, dlen); - switch_xml_set_txt_d(variable, data); - free(data); + if (hi->idx) { + int i; + + for (i = 0; i < hi->idx; i++) { + off = switch_ivr_set_xml_chan_var(xml, hi->name, hi->array[i], off); } + } else { + off = switch_ivr_set_xml_chan_var(xml, hi->name, hi->value, off); } } switch_channel_variable_last(channel); diff --git a/src/switch_regex.c b/src/switch_regex.c index 787ab0dcf4..7bce6ce461 100644 --- a/src/switch_regex.c +++ b/src/switch_regex.c @@ -129,7 +129,7 @@ SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_c char *substituted, switch_size_t len, int *ovector) { char index[10] = ""; - char replace[1024] = ""; + const char *replace = NULL; switch_size_t x, y = 0, z = 0; int num = 0; @@ -154,11 +154,12 @@ SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_c num = -1; } - if (pcre_copy_substring(field_data, ovector, match_count, num, replace, sizeof(replace)) > 0) { + if (pcre_get_substring(field_data, ovector, match_count, num, &replace) > 0) { switch_size_t r; for (r = 0; r < strlen(replace); r++) { substituted[y++] = replace[r]; } + pcre_free_substring(replace); } } else { substituted[y++] = data[x]; @@ -168,6 +169,24 @@ SWITCH_DECLARE(void) switch_perform_substitution(switch_regex_t *re, int match_c substituted[y++] = '\0'; } + +SWITCH_DECLARE(void) switch_capture_regex(switch_regex_t *re, int match_count, const char *field_data, + int *ovector, const char *var, switch_cap_callback_t callback, void *user_data) + +{ + + + const char *replace; + int i; + + for (i = 0; i < match_count; i++) { + if (pcre_get_substring(field_data, ovector, match_count, i, &replace) > 0) { + callback(var, replace, user_data); + pcre_free_substring(replace); + } + } +} + SWITCH_DECLARE(switch_status_t) switch_regex_match_partial(const char *target, const char *expression, int *partial) { const char *error = NULL; /* Used to hold any errors */