]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
add arrays to event headers and chanvars
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 25 May 2011 20:42:36 +0000 (15:42 -0500)
committerAnthony Minessale <anthm@freeswitch.org>
Wed, 25 May 2011 20:42:36 +0000 (15:42 -0500)
16 files changed:
libs/esl/Makefile
libs/esl/src/esl.c
libs/esl/src/esl_event.c
libs/esl/src/include/esl.h
libs/esl/src/include/esl_event.h
src/include/switch_channel.h
src/include/switch_event.h
src/include/switch_regex.h
src/include/switch_types.h
src/mod/applications/mod_dptools/mod_dptools.c
src/mod/dialplans/mod_dialplan_xml/mod_dialplan_xml.c
src/mod/endpoints/mod_sofia/sofia_glue.c
src/switch_channel.c
src/switch_event.c
src/switch_ivr.c
src/switch_regex.c

index 7363304cdb49197b2dd4002b85c4ccc31a3d5c27..60bae27b5f3465b4bd6db6a6f91c6d96632ef852 100644 (file)
@@ -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:
index bfdf58a62510320e34a6972b5eacf69f5344d83e..675ecee46007744231e9b41b750d0703b5926e85 100644 (file)
@@ -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;
+}
 
index 9bd78a838d95f84ded3eb8fd63a68af5e85b4c78..614d1b6190e04251c24268db7fed72b95bc27359 100644 (file)
@@ -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,15 +243,36 @@ 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;
 }
 
@@ -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);
+
+                       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 ((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 ((event->flags & ESL_UNIQ_HEADERS)) {
-               esl_event_del_header(event, header_name);
+                       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) {
-                       event->last_header = 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 {
-               if (event->last_header) {
-                       event->last_header->next = header;
-               } 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;
-                       header->next = NULL;
+                       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;
                }
-               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(ep->body);
+               FREE(ep->subclass_name);
+#ifdef ESL_EVENT_RECYCLE
+               if (esl_queue_trypush(EVENT_RECYCLE_QUEUE, ep) != ESL_SUCCESS) {
+                       FREE(ep);
                }
-               FREE(this_event->body);
-               FREE(this_event->subclass_name);
-               memset(this_event, 0, sizeof(*this_event));
-               FREE(this_event);
+#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:
index 17ebf26ee142c20d28afae6c769b99d4f4e8dcb7..095e814a0e364896270f72d2cc3f9a0bb108b0c4 100644 (file)
@@ -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)
 
index 7e619f47642902ad4151d12ebb50dd14b6951211..10af7264b9e4a52a31143d32889dd00ebd033583 100644 (file)
@@ -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
index dc8175b202245b626e9801b553446d2b4b0877a4..40d4ee6b13d1e6ff1fc13d15d5f5ddfaae81a85e 100644 (file)
@@ -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);
 
index 9046bc711a20aca177e6a0d99192ff07eb760e39..642e39afeba149a0e74a70e326fc5621d2646029 100644 (file)
@@ -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))
 
index 96d623043c561e9adcaaa84fb53337c5a8827311..4c5f14961f47dec5d8cb2e804c728573261b5ae3 100644 (file)
@@ -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);\
index 6664dc06535fa3cd9f93099584159a37b940ebec..2b2b3de45d4798cb28276ae0313507ec4a95c5ac 100644 (file)
@@ -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 *);
index 5b982111d57709f16269ff29bd26883d83e5b2a8..88bcaf86b62963fa08f4e5f6b4587a2ffe6b3b66 100755 (executable)
@@ -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, "<varname>=<value>",
                                   SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
+
+       SWITCH_ADD_APP(app_interface, "push", "Set a channel variable", SET_LONG_DESC, push_function, "<varname>=<value>",
+                                  SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
+
+       SWITCH_ADD_APP(app_interface, "unshift", "Set a channel variable", SET_LONG_DESC, unshift_function, "<varname>=<value>",
+                                  SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC);
+
        SWITCH_ADD_APP(app_interface, "set_global", "Set a global variable", SET_GLOBAL_LONG_DESC, set_global_function, "<varname>=<value>",
                                   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,
index 929372be1aab1b936959c7d29303969bb55c8e4d..3b5f6995e497b467e2a50ae2203ea9773f478fba 100644 (file)
@@ -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");
index 2724e5e562728e3387f17764c2abf1398343b0d3..8af77a17d77fb2e926b5b7e673537df19f161a86 100644 (file)
@@ -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"));
                }
        }
index 76538bdaa6d7951caa7f63624d39ced8353939f7..d31b75e4780c3d16e1ed930479d0dc153c5a2bbd 100644 (file)
@@ -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);
index 6d970419014b00caa541ee88282c73eec9bcac35..0d5b3c3665e1e7543c1bfd1c7bb68fabf05f476d 100644 (file)
@@ -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;
-       } else {
+               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);
+                       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));
 
-       if (switch_test_flag(event, EF_UNIQ_HEADERS)) {
-               switch_event_del_header(event, header_name);
+               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;
+               }
 
-       memset(header, 0, sizeof(*header));
+               i = header->idx + 1;
+               m = realloc(header->array, sizeof(char *) * i); 
+               switch_assert(m);
 
-       header->name = DUP(header_name);
-       header->value = data;
-       header->hash = switch_ci_hashfunc_default(header->name, &hlen);
+               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;
+               }
 
-       if ((stack & SWITCH_STACK_TOP)) {
-               header->next = event->headers;
-               event->headers = header;
-               if (!event->last_header) {
-                       event->last_header = header;
+               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 {
-               if (event->last_header) {
-                       event->last_header->next = header;
-               } else {
+               header->value = data;
+       }
+
+       if (!exists) {
+               header->hash = switch_ci_hashfunc_default(header->name, &hlen);
+
+               if ((stack & SWITCH_STACK_TOP)) {
+                       header->next = event->headers;
                        event->headers = header;
-                       header->next = NULL;
+                       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;
                }
-               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;
index 74c8f7efd09443cf9d2f5d8f5178e4c5c76f7e71..5ab9f440c7bc3084e3d038a1fa9ff679daa2a079 100644 (file)
@@ -1982,25 +1982,43 @@ SWITCH_DECLARE(int) switch_ivr_set_xml_profile_data(switch_xml_t xml, switch_cal
        return off;
 }
 
-SWITCH_DECLARE(int) switch_ivr_set_xml_chan_vars(switch_xml_t xml, switch_channel_t *channel, int 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_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);
index 787ab0dcf4f0de6ef6af88ea1e31564647584771..7bce6ce461426f6d41697b899ed1a3428b1087ce 100644 (file)
@@ -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                                           */