]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
more ivr goodies
authorAnthony Minessale <anthony.minessale@gmail.com>
Wed, 1 Mar 2006 00:58:32 +0000 (00:58 +0000)
committerAnthony Minessale <anthony.minessale@gmail.com>
Wed, 1 Mar 2006 00:58:32 +0000 (00:58 +0000)
git-svn-id: http://svn.freeswitch.org/svn/freeswitch/trunk@705 d0543943-73ff-0310-b7d9-9358b9ac24b2

src/include/switch_ivr.h
src/mod/applications/mod_bridgecall/mod_bridgecall.c
src/mod/applications/mod_ivrtest/mod_ivrtest.c
src/mod/endpoints/mod_iax/mod_iax.c
src/mod/languages/mod_spidermonkey/Makefile
src/mod/languages/mod_spidermonkey/mod_spidermonkey.c
src/switch_ivr.c

index b67c3885732f1980d38dd011f4da035499050ca8..31f45a09ced336eedab5699a2ff9ab19fea81873 100644 (file)
@@ -80,7 +80,9 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
                                                                                                                          unsigned int buflen,
                                                                                                                          unsigned int maxdigits,
                                                                                                                          const char *terminators,
-                                                                                                                         char *terminator);
+                                                                                                                         char *terminator,
+                                                                                                                         unsigned int timeout,
+                                                              unsigned int poll_channel);
        
 /*!
   \brief play a file from the disk to the session
@@ -121,6 +123,18 @@ SWITCH_DECLARE(switch_status) switch_ivr_record_file(switch_core_session *sessio
                                                                                                         unsigned int buflen);
 
 
+/*!
+  \brief Speak given text with given tts engine
+  \param session the session to speak on
+  \param voice_name the desired voice
+  \param timer_name optional timer to use for async behaviour
+  \param rate the sample rate
+  \param dtmf_callback code to execute if any dtmf is dialed during the audio
+  \param text the text to speak
+  \param buf an option data pointer to pass to the callback or a string to put encountered digits in
+  \param buflen the len of buf
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
 SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session, 
                                                                                                        char *tts_name,
                                                                                                        char *voice_name,
@@ -131,6 +145,17 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session
                                                                                                        void *buf,
                                                                                                        unsigned int buflen);
 
+/*!
+  \brief Bridge Audio from one session to another
+  \param session one session
+  \param peer_session the other session
+  \param timelimit maximum number of seconds to wait for both channels to be answered
+  \return SWITCH_STATUS_SUCCESS if all is well
+*/
+SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_session *session, 
+                                                                                                                          switch_core_session *peer_session,
+                                                                                                                          unsigned int timelimit);
+
 /** @} */
 
 #ifdef __cplusplus
index a5c3ec210fdd1e9fea5797e3b8c41a775bfa7024..89051a02e4042c5071469f27cef16cde5fdf5db7 100644 (file)
 
 static const char modname[] = "mod_bridgecall";
 
-struct audio_bridge_data {
-       switch_core_session *session_a;
-       switch_core_session *session_b;
-       int running;
-};
-
-static void *audio_bridge_thread(switch_thread *thread, void *obj)
-{
-       struct switch_core_thread_session *data = obj;
-       int *stream_id_p;
-       int stream_id = 0, ans_a = 0, ans_b = 0;
-       
-       switch_channel *chan_a, *chan_b;
-       switch_frame *read_frame;
-       switch_core_session *session_a, *session_b;
-
-       session_a = data->objs[0];
-       session_b = data->objs[1];
-
-       stream_id_p = data->objs[2];
-       if (stream_id_p) {
-               stream_id = *stream_id_p;
-       }
-
-       chan_a = switch_core_session_get_channel(session_a);
-       chan_b = switch_core_session_get_channel(session_b);
-
-
-       ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
-       ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
-
-
-       while (data->running > 0) {
-               switch_channel_state b_state = switch_channel_get_state(chan_b);
-
-               switch (b_state) {
-               case CS_HANGUP:
-                       data->running = -1;
-                       continue;
-                       break;
-               default:
-                       break;
-               }
-
-               /* If this call is running on early media and it answers for real, pass it along... */
-               if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
-                       if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
-                               switch_channel_answer(chan_b);
-                       }
-                       ans_b++;
-               }
-
-               if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
-                       if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
-                               switch_channel_answer(chan_a);
-                       }
-                       ans_a++;
-               }
-
-               /* if 1 channel has DTMF pass it to the other */
-               if (switch_channel_has_dtmf(chan_a)) {
-                       char dtmf[128];
-                       switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
-                       switch_core_session_send_dtmf(session_b, dtmf);
-               }
-
-               /* read audio from 1 channel and write it to the other */
-               if (switch_core_session_read_frame(session_a, &read_frame, -1, stream_id) == SWITCH_STATUS_SUCCESS
-                       && read_frame->datalen) {
-                       if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
-                               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "write: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_b));
-                               data->running = -1;
-                       }
-               } else {
-                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "read: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_a));
-                       data->running = -1;
-               }
-
-       }
-       switch_channel_hangup(chan_b);
-       data->running = 0;
-
-       return NULL;
-}
-
-
-static switch_status audio_bridge_on_hangup(switch_core_session *session)
-{
-       switch_core_session *other_session;
-       switch_channel *channel = NULL, *other_channel = NULL;
-
-       channel = switch_core_session_get_channel(session);
-       assert(channel != NULL);
-
-       other_session = switch_channel_get_private(channel);
-       assert(other_session != NULL);
-
-       other_channel = switch_core_session_get_channel(other_session);
-       assert(other_channel != NULL);
-
-       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM HANGUP %s kill %s\n", switch_channel_get_name(channel),
-                                                 switch_channel_get_name(other_channel));
-
-       switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL);
-       switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
-
-       return SWITCH_STATUS_SUCCESS;
-}
-
-static switch_status audio_bridge_on_ring(switch_core_session *session)
-{
-       switch_channel *channel = NULL;
-
-       channel = switch_core_session_get_channel(session);
-       assert(channel != NULL);
-
-       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM RING\n");
-
-       /* put the channel in a passive state so we can loop audio to it */
-       if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
-               switch_channel_set_state(channel, CS_TRANSMIT);
-               return SWITCH_STATUS_FALSE;
-       }
-
-
-       return SWITCH_STATUS_SUCCESS;
-}
-
-static const switch_state_handler_table audio_bridge_peer_state_handlers = {
-       /*.on_init */ NULL,
-       /*.on_ring */ audio_bridge_on_ring,
-       /*.on_execute */ NULL,
-       /*.on_hangup */ audio_bridge_on_hangup,
-       /*.on_loopback */ NULL,
-       /*.on_transmit */ NULL
-};
-
-static const switch_state_handler_table audio_bridge_caller_state_handlers = {
-       /*.on_init */ NULL,
-       /*.on_ring */ NULL,
-       /*.on_execute */ NULL,
-       /*.on_hangup */ audio_bridge_on_hangup,
-       /*.on_loopback */ NULL,
-       /*.on_transmit */ NULL
-};
-
 static void audio_bridge_function(switch_core_session *session, char *data)
 {
-       switch_channel *caller_channel, *peer_channel;
+       switch_channel *caller_channel;
        switch_core_session *peer_session;
        switch_caller_profile *caller_profile, *caller_caller_profile;
        char chan_type[128] = { '\0' }, *chan_data;
-       int timelimit = 60;                     /* probably a useful option to pass in when there's time */
+       unsigned int timelimit = 60;                    /* probably a useful option to pass in when there's time */
        caller_channel = switch_core_session_get_channel(session);
        assert(caller_channel != NULL);
 
@@ -211,76 +65,12 @@ static void audio_bridge_function(switch_core_session *session, char *data)
 
        if (switch_core_session_outgoing_channel(session, chan_type, caller_profile, &peer_session) !=
                SWITCH_STATUS_SUCCESS) {
-               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "DOH!\n");
+               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Cannot Create Outgoing Channel!\n");
                switch_channel_hangup(caller_channel);
                return;
        } else {
-               struct switch_core_thread_session this_audio_thread, other_audio_thread;
-               time_t start;
-               int stream_id = 0;
-
-               peer_channel = switch_core_session_get_channel(peer_session);
-               memset(&other_audio_thread, 0, sizeof(other_audio_thread));
-               memset(&this_audio_thread, 0, sizeof(this_audio_thread));
-               other_audio_thread.objs[0] = session;
-               other_audio_thread.objs[1] = peer_session;
-               other_audio_thread.objs[2] = &stream_id;
-               other_audio_thread.running = 5;
-
-               this_audio_thread.objs[0] = peer_session;
-               this_audio_thread.objs[1] = session;
-               this_audio_thread.objs[2] = &stream_id;
-               this_audio_thread.running = 2;
-
-
-               switch_channel_set_private(caller_channel, peer_session);
-               switch_channel_set_private(peer_channel, session);
-               switch_channel_add_state_handler(caller_channel, &audio_bridge_caller_state_handlers);
-               switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
-               switch_core_session_thread_launch(peer_session);
-
-               for (;;) {
-                       int state = switch_channel_get_state(peer_channel);
-                       if (state > CS_RING) {
-                               break;
-                       }
-                       switch_yield(1000);
-               }
-
-               time(&start);
-               while (switch_channel_get_state(caller_channel) == CS_EXECUTE &&
-                          switch_channel_get_state(peer_channel) == CS_TRANSMIT &&
-                          !switch_channel_test_flag(peer_channel, CF_ANSWERED) &&
-                          !switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) &&
-                          ((time(NULL) - start) < timelimit)) {
-                       switch_yield(20000);
-               }
-
-               if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
-                       switch_channel_answer(caller_channel);
-               }
-
-               if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || 
-                       switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
-
-                       switch_core_session_launch_thread(session, audio_bridge_thread, (void *) &other_audio_thread);
-                       audio_bridge_thread(NULL, (void *) &this_audio_thread);
-
-                       switch_channel_hangup(peer_channel);
-                       if (other_audio_thread.running > 0) {
-                               other_audio_thread.running = -1;
-                               /* wait for the other audio thread */
-                               while (other_audio_thread.running) {
-                                       switch_yield(1000);
-                               }
-                       }
-
-
-               }
+               switch_ivr_multi_threaded_bridge(session, peer_session, timelimit);
        }
-
-       switch_channel_hangup(caller_channel);
-       switch_channel_hangup(peer_channel);
 }
 
 
index f617b1d9b00dee668d89baa6dcf55b590e38d51c..4c5fdc3f15b956fd5d6ae0d855dcb60f44770a76 100644 (file)
@@ -157,7 +157,7 @@ static void ivrtest_function(switch_core_session *session, char *data)
                        }
                }
 
-               if (switch_ivr_collect_digits_count(session, buf, sizeof(buf), 10, "#*", &term) != SWITCH_STATUS_SUCCESS) {
+               if (switch_ivr_collect_digits_count(session, buf, sizeof(buf), 10, "#*", &term, 10000, 1) != SWITCH_STATUS_SUCCESS) {
                        switch_channel_hangup(channel);
                        break;
                }
index de72c57b730b0c5f5cf3eec4bbf58f7527e2f004..a1952674fbb5e8631cfe44526aa1603215abaec2 100644 (file)
@@ -857,7 +857,9 @@ SWITCH_MOD_DECLARE(switch_status) switch_module_runtime(void)
        int refresh;
        struct iax_event *iaxevent = NULL;
        switch_event *s_event;
-       load_config();
+       if (load_config() != SWITCH_STATUS_SUCCESS) {
+               return SWITCH_STATUS_TERM;
+       }
 
        if (globals.debug) {
                iax_enable_debug();
index fb0ae3d9f43c652e931cf1cd429a9d3bfc66b4de..e4933d5bcc69dbae465af46878d2697782b282e4 100644 (file)
@@ -69,6 +69,7 @@ all:  depends $(MODNAME).so
 
 depends:
        MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) mozilla --prefix=$(PREFIX)
+       MAKE=$(MAKE) $(BASE)/build/buildlib.sh $(BASE) install curl-7.15.2.tar.gz --prefix=$(PREFIX)
 
 $(MODNAME).so: $(MODNAME).c
        $(CC) $(CFLAGS) -fPIC -c $(MODNAME).c -o $(MODNAME).o 
index b84351f7e1b14d23ea22d5e635e8c9a1388b4d8a..c78d902d02bebe070f67e54b8dbf9ee7de6ea453 100644 (file)
@@ -29,6 +29,8 @@
  * mod_spidermonkey.c -- Javascript Module
  *
  */
+#define HAVE_CURL
+
 #include "jstypes.h"
 #include "jsarena.h"
 #include "jsutil.h"
@@ -47,6 +49,9 @@
 #include "jsscript.h"
 #include <libteletone.h>
 #include <switch.h>
+#ifdef HAVE_CURL
+#include <curl/curl.h>
+#endif
 
 #ifdef _MSC_VER
 #pragma warning(disable: 4311)
@@ -68,7 +73,6 @@ static struct {
 } globals;
 
 
-//extern JSClass global_class;
 static JSClass global_class = {
     "Global", JSCLASS_HAS_PRIVATE, 
     JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub,  JS_PropertyStub, 
@@ -303,11 +307,12 @@ static JSBool session_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *arg
        char *tts_name = NULL;
        char *voice_name = NULL;
        char *text = NULL;
+       char *dtmf_callback = NULL;
        switch_codec *codec;
-       char buf[10] = "";
        void *bp = NULL;
        int len = 0;
-       //switch_dtmf_callback_function dtmf_func = NULL;
+       struct dtmf_callback_state cb_state = {0};
+       switch_dtmf_callback_function dtmf_func = NULL;
 
        channel = switch_core_session_get_channel(jss->session);
     assert(channel != NULL);
@@ -322,8 +327,18 @@ static JSBool session_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *arg
                text = JS_GetStringBytes(JS_ValueToString(cx, argv[2]));
        }
        if (argc > 3) {
-               bp = buf;
-               len = sizeof(buf);
+               dtmf_callback = JS_GetStringBytes(JS_ValueToString(cx, argv[3]));
+               if (switch_strlen_zero(dtmf_callback)) {
+                       dtmf_callback = NULL;
+               } else {
+                       memset(&cb_state, 0, sizeof(cb_state));
+                       switch_copy_string(cb_state.code_buffer, dtmf_callback, sizeof(cb_state.code_buffer));
+                       cb_state.code_buffer_len = strlen(cb_state.code_buffer);
+                       cb_state.session_state = jss;
+                       dtmf_func = js_dtmf_callback;
+                       bp = &cb_state;
+                       len = sizeof(cb_state);
+               }
        }
 
        if (!tts_name && text) {
@@ -336,15 +351,14 @@ static JSBool session_speak(JSContext *cx, JSObject *obj, uintN argc, jsval *arg
                                                  voice_name && strlen(voice_name) ? voice_name : NULL, 
                                                  NULL,
                                                  codec->implementation->samples_per_second,
-                                                 NULL,
+                                                 dtmf_func,
                                                  text,
                                                  bp,
                                                  len);
-       if(len) {
-               *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
-       }
-       return JS_TRUE;
-       
+
+       *rval = STRING_TO_JSVAL (JS_NewStringCopyZ(cx, cb_state.ret_buffer));
+
+       return (switch_channel_get_state(channel) == CS_EXECUTE) ? JS_TRUE : JS_FALSE;
 }
 
 static JSBool session_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
@@ -353,15 +367,24 @@ static JSBool session_get_digits(JSContext *cx, JSObject *obj, uintN argc, jsval
        char *terminators = NULL;
        char *buf;
        int digits;
-
+       int32 timeout = 5000;
+       int32 poll_chan = 1;
+       
+       
        if (argc > 0) {
                char term;
                digits = atoi(JS_GetStringBytes(JS_ValueToString(cx, argv[0])));
                if (argc > 1) {
                        terminators = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
                }
+               if (argc > 2) {
+                       JS_ValueToInt32(cx, argv[2], &timeout);
+               }
+               if (argc > 3) {
+                       JS_ValueToInt32(cx, argv[3], &poll_chan);
+               }
                buf = switch_core_session_alloc(jss->session, digits);
-               switch_ivr_collect_digits_count(jss->session, buf, digits, digits, terminators, &term);
+               switch_ivr_collect_digits_count(jss->session, buf, digits, digits, terminators, &term, timeout, poll_chan ? SWITCH_TRUE : SWITCH_FALSE);
                *rval = STRING_TO_JSVAL ( JS_NewStringCopyZ(cx, buf) );
                return JS_TRUE;
        }
@@ -381,6 +404,95 @@ static JSBool session_answer(JSContext *cx, JSObject *obj, uintN argc, jsval *ar
        return JS_TRUE;
 }
 
+#ifdef HAVE_CURL
+
+struct config_data {
+       JSContext *cx;
+       JSObject *obj;
+       char *name;
+};
+
+static size_t realtime_callback(void *ptr, size_t size, size_t nmemb, void *data)
+{
+    register int realsize = size * nmemb;
+       char *line, lineb[2048], *nextline = NULL, *val = NULL, *p = NULL;
+       jsval rval;
+       struct config_data *config_data = data;
+       char code[256];
+
+       if (config_data->name) {
+               switch_copy_string(lineb, (char *) ptr, sizeof(lineb));
+               line = lineb;
+               while (line) {
+                       if ((nextline = strchr(line, '\n'))) {
+                               *nextline = '\0';
+                               nextline++;
+                       }
+                       
+                       if ((val = strchr(line, '='))) {
+                *val = '\0';
+                val++;
+                if (val[0] == '>') {
+                    *val = '\0';
+                    val++;
+                }
+                               
+                for (p = line; p && *p == ' '; p++);
+                line = p;
+                for (p=line+strlen(line)-1;*p == ' '; p--)
+                    *p = '\0';
+                for (p = val; p && *p == ' '; p++);
+                val = p;
+                for (p=val+strlen(val)-1;*p == ' '; p--)
+                    *p = '\0';
+
+                               snprintf(code, sizeof(code), "~%s[\"%s\"] = \"%s\"", config_data->name, line, val);
+                               eval_some_js(code, config_data->cx, config_data->obj, &rval);
+
+            }
+
+                       line = nextline;
+               }
+       } 
+       return realsize;
+
+}
+
+
+static JSBool js_fetchurl(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+       char *url = NULL, *name = NULL;
+       CURL *curl_handle = NULL;
+       struct config_data config_data;
+       
+       if ( argc > 0 && (url = JS_GetStringBytes(JS_ValueToString(cx, argv[0])))) {
+               if (argc > 1)
+                       name = JS_GetStringBytes(JS_ValueToString(cx, argv[1]));
+               curl_global_init(CURL_GLOBAL_ALL);
+               curl_handle = curl_easy_init();
+               if (!strncasecmp(url, "https", 5)) {
+                       curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0);
+                       curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0);
+               }
+               config_data.cx = cx;
+               config_data.obj = obj;
+               if (name)
+                       config_data.name = name;
+               curl_easy_setopt(curl_handle, CURLOPT_URL, url);
+               curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, realtime_callback);
+               curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)&config_data);
+               curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "asterisk-js/1.0");
+               curl_easy_perform(curl_handle);
+               curl_easy_cleanup(curl_handle);
+    } else {
+               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Error!\n");
+               return JS_FALSE;
+       }
+
+       return JS_TRUE;
+}
+#endif
+
 /* Session Object */
 /*********************************************************************************/
 enum session_tinyid {
@@ -643,7 +755,6 @@ static JSBool teletone_generate(JSContext *cx, JSObject *obj, uintN argc, jsval
 
                        write_frame.samples = write_frame.datalen / 2;
                        for (stream_id = 0; stream_id < switch_core_session_get_stream_count(session); stream_id++) {
-
                                if (switch_core_session_write_frame(session, &write_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
                                        switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Bad Write\n");
                                        break;
@@ -651,7 +762,9 @@ static JSBool teletone_generate(JSContext *cx, JSObject *obj, uintN argc, jsval
                        }
                }
 
-               switch_core_thread_session_end(&thread_session);
+               if (tto->timer) {
+                       switch_core_thread_session_end(&thread_session);
+               }
                return JS_TRUE;
        }
        
@@ -704,9 +817,158 @@ static JSBool js_log(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsva
        return JS_FALSE;
 }
 
+static JSBool js_include(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+       char *code;
+       if ( argc > 0 && (code = JS_GetStringBytes(JS_ValueToString(cx, argv[0])))) {
+               eval_some_js(code, cx, obj, rval);
+               return JS_TRUE;
+       }
+       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Invalid Arguements\n");
+       return JS_FALSE;
+}
+
+#define B64BUFFLEN 1024
+static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static int write_buf(int fd, char *buf) {
+
+       size_t len = strlen(buf);
+       if (fd && write(fd, buf, len) != len) {
+               close(fd);
+               return 0;
+       }
+
+       return 1;
+}
+
+static JSBool js_email(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
+{
+       char *to = NULL, *from = NULL, *headers, *body = NULL, *file = NULL;
+       char *bound = "XXXX_boundary_XXXX";
+       char filename[80], buf[B64BUFFLEN];
+       int fd = 0, ifd = 0;
+       int x=0, y=0, bytes=0, ilen=0;
+       unsigned int b=0, l=0;
+       unsigned char in[B64BUFFLEN];
+       unsigned char out[B64BUFFLEN+512];
+       char *path = NULL;
+
+       
+       if ( 
+                argc > 3 && 
+                (from = JS_GetStringBytes(JS_ValueToString(cx, argv[0]))) &&
+                (to = JS_GetStringBytes(JS_ValueToString(cx, argv[1]))) &&
+                (headers = JS_GetStringBytes(JS_ValueToString(cx, argv[2]))) &&
+                (body = JS_GetStringBytes(JS_ValueToString(cx, argv[3]))) 
+                ) {
+               if ( argc > 4)
+                       file = JS_GetStringBytes(JS_ValueToString(cx, argv[4]));
+               
+               
+               snprintf(filename, 80, "/tmp/mail.%ld", switch_time_now());
+
+               if ((fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644))) {
+                       if (file) {
+                               path = file;
+                               if ((ifd = open(path, O_RDONLY)) < 1) {
+                                       return JS_FALSE;
+                               }
+
+                               snprintf(buf, B64BUFFLEN, "MIME-Version: 1.0\nContent-Type: multipart/mixed; boundary=\"%s\"\n", bound);
+                               if (!write_buf(fd, buf)) {
+                                       return JS_FALSE;
+                               }
+                       }
+                       
+                       if (!write_buf(fd, headers))
+                               return JS_FALSE;
+
+                       if (!write_buf(fd, "\n\n"))
+                               return JS_FALSE;
+                       
+                       if (file) {
+                               snprintf(buf, B64BUFFLEN, "--%s\nContent-Type: text/plain\n\n", bound);
+                               if (!write_buf(fd, buf))
+                                       return JS_FALSE;
+                       }
+                       
+                       if (!write_buf(fd, body))
+                               return JS_FALSE;
+                       
+                       if (file) {
+                               snprintf(buf, B64BUFFLEN, "\n\n--%s\nContent-Type: application/octet-stream\nContent-Transfer-Encoding: base64\nContent-Description: Sound attachment.\nContent-Disposition: attachment; filename=\"%s\"\n\n", bound, file);
+                               if (!write_buf(fd, buf))
+                                       return JS_FALSE;
+                               
+                               while((ilen=read(ifd, in, B64BUFFLEN))) {
+                                       for (x=0;x<ilen;x++) {
+                                               b = (b<<8) + in[x];
+                                               l += 8;
+                                               while (l >= 6) {
+                                                       out[bytes++] = c64[(b>>(l-=6))%64];
+                                                       if (++y!=72)
+                                                               continue;
+                                                       out[bytes++] = '\n';
+                                                       y=0;
+                                               }
+                                       }
+                                       if (write(fd, &out, bytes) != bytes) { 
+                                               return -1;
+                                       } else 
+                                               bytes=0;
+                                       
+                               }
+                               
+                               if (l > 0)
+                                       out[bytes++] = c64[((b%16)<<(6-l))%64];
+                               if (l != 0) while (l < 6)
+                                       out[bytes++] = '=', l += 2;
+       
+                               if (write(fd, &out, bytes) != bytes) { 
+                                       return -1;
+                               }
+
+                       }
+                       
+
+                       
+                       if (file) {
+                               snprintf(buf, B64BUFFLEN, "\n\n--%s--\n.\n", bound);
+                               if (!write_buf(fd, buf))
+                                       return JS_FALSE;
+                       }
+               }
+
+               if (fd)
+                       close(fd);
+               if (ifd)
+                       close(ifd);
+
+               snprintf(buf, B64BUFFLEN, "/bin/cat %s | /usr/sbin/sendmail -tf \"%s\" %s", filename, from, to);
+               system(buf);
+               unlink(filename);
+
+
+               if (file) {
+                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Emailed file [%s] to [%s]\n", filename, to);
+               } else {
+                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "Emailed data to [%s]\n", to);
+               }
+               return JS_TRUE;
+       }
+       
+
+       return JS_FALSE;
+}
 
 static JSFunctionSpec fs_functions[] = {
        {"console_log", js_log, 2}, 
+       {"include", js_include, 1}, 
+       {"email", js_email, 2}, 
+#ifdef HAVE_CURL
+       {"fetchURL", js_fetchurl, 1}, 
+#endif 
        {0}
 };
 
index d1693e3cf60895a07a0f554ff125e9ecdde4ac2e..81a546223ea15d36730ee3a31fd64aacf6655a67 100644 (file)
@@ -77,27 +77,44 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
                                                                                                                          unsigned int buflen,
                                                                                                                          unsigned int maxdigits,
                                                                                                                          const char *terminators,
-                                                                                                                         char *terminator)
+                                                                                                                         char *terminator,
+                                                                                                                         unsigned int timeout,
+                                                                                                                         unsigned int poll_channel
+                                                                                                                         )
 {
        unsigned int i = 0, x =  (unsigned int) strlen(buf);
        switch_channel *channel;
        switch_status status = SWITCH_STATUS_SUCCESS;
-       
+       switch_time_t started = 0;
+       unsigned int elapsed;
+
        channel = switch_core_session_get_channel(session);
     assert(channel != NULL);
 
        *terminator = '\0';
 
-       for (i = 0 ; i < x; i++) {
-               if (strchr(terminators, buf[i])) {
-                       *terminator = buf[i];
-                       return SWITCH_STATUS_SUCCESS;
+       if (terminators) {
+               for (i = 0 ; i < x; i++) {
+                       if (strchr(terminators, buf[i])) {
+                               *terminator = buf[i];
+                               return SWITCH_STATUS_SUCCESS;
+                       }
                }
        }
 
+       if (timeout) {
+               started = switch_time_now();
+       }
        while (switch_channel_get_state(channel) == CS_EXECUTE) {
                switch_frame *read_frame;
 
+               if (timeout) {
+                       elapsed = (switch_time_now() - started) / 1000;
+                       if (elapsed >= timeout) {
+                               break;
+                       }
+               }
+               
                if (switch_channel_has_dtmf(channel)) {
                        char dtmf[128];
                        switch_channel_dequeue_dtmf(channel, dtmf, sizeof(dtmf));
@@ -116,9 +133,12 @@ SWITCH_DECLARE(switch_status) switch_ivr_collect_digits_count(switch_core_sessio
                                }
                        }
                }
-               
-               if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
-                       break;
+               if (poll_channel) {
+                       if ((status = switch_core_session_read_frame(session, &read_frame, -1, 0)) != SWITCH_STATUS_SUCCESS) {
+                               break;
+                       }
+               } else {
+                       switch_yield(1000);
                }
        }
 
@@ -639,7 +659,7 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session
                }
        }
 
-       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done playing file\n");
+       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "done speaking text\n");
        switch_core_codec_destroy(&codec);
        flags = 0;
        switch_core_codec_destroy(&codec);
@@ -654,4 +674,225 @@ SWITCH_DECLARE(switch_status) switch_ivr_speak_text(switch_core_session *session
 }
 
 
+/* Bridge Related Stuff*/
+/*********************************************************************************/
+struct audio_bridge_data {
+       switch_core_session *session_a;
+       switch_core_session *session_b;
+       int running;
+};
+
+static void *audio_bridge_thread(switch_thread *thread, void *obj)
+{
+       struct switch_core_thread_session *data = obj;
+       int *stream_id_p;
+       int stream_id = 0, ans_a = 0, ans_b = 0;
+       
+       switch_channel *chan_a, *chan_b;
+       switch_frame *read_frame;
+       switch_core_session *session_a, *session_b;
+
+       session_a = data->objs[0];
+       session_b = data->objs[1];
+
+       stream_id_p = data->objs[2];
+       if (stream_id_p) {
+               stream_id = *stream_id_p;
+       }
+
+       chan_a = switch_core_session_get_channel(session_a);
+       chan_b = switch_core_session_get_channel(session_b);
+
+
+       ans_a = switch_channel_test_flag(chan_a, CF_ANSWERED);
+       ans_b = switch_channel_test_flag(chan_b, CF_ANSWERED);
+
+
+       while (data->running > 0) {
+               switch_channel_state b_state = switch_channel_get_state(chan_b);
+
+               switch (b_state) {
+               case CS_HANGUP:
+                       data->running = -1;
+                       continue;
+                       break;
+               default:
+                       break;
+               }
+
+               /* If this call is running on early media and it answers for real, pass it along... */
+               if (!ans_b && switch_channel_test_flag(chan_a, CF_ANSWERED)) {
+                       if (!switch_channel_test_flag(chan_b, CF_ANSWERED)) {
+                               switch_channel_answer(chan_b);
+                       }
+                       ans_b++;
+               }
+
+               if (!ans_a && switch_channel_test_flag(chan_b, CF_ANSWERED)) {
+                       if (!switch_channel_test_flag(chan_a, CF_ANSWERED)) {
+                               switch_channel_answer(chan_a);
+                       }
+                       ans_a++;
+               }
+
+               /* if 1 channel has DTMF pass it to the other */
+               if (switch_channel_has_dtmf(chan_a)) {
+                       char dtmf[128];
+                       switch_channel_dequeue_dtmf(chan_a, dtmf, sizeof(dtmf));
+                       switch_core_session_send_dtmf(session_b, dtmf);
+               }
+
+               /* read audio from 1 channel and write it to the other */
+               if (switch_core_session_read_frame(session_a, &read_frame, -1, stream_id) == SWITCH_STATUS_SUCCESS
+                       && read_frame->datalen) {
+                       if (switch_core_session_write_frame(session_b, read_frame, -1, stream_id) != SWITCH_STATUS_SUCCESS) {
+                               switch_console_printf(SWITCH_CHANNEL_CONSOLE, "write: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_b));
+                               data->running = -1;
+                       }
+               } else {
+                       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "read: %s Bad Frame.... Bubye!\n", switch_channel_get_name(chan_a));
+                       data->running = -1;
+               }
+
+       }
+       switch_channel_hangup(chan_b);
+       data->running = 0;
+
+       return NULL;
+}
+
+
+static switch_status audio_bridge_on_hangup(switch_core_session *session)
+{
+       switch_core_session *other_session;
+       switch_channel *channel = NULL, *other_channel = NULL;
+
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+
+       other_session = switch_channel_get_private(channel);
+       assert(other_session != NULL);
+
+       other_channel = switch_core_session_get_channel(other_session);
+       assert(other_channel != NULL);
 
+       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM HANGUP %s kill %s\n", switch_channel_get_name(channel),
+                                                 switch_channel_get_name(other_channel));
+
+       switch_core_session_kill_channel(other_session, SWITCH_SIG_KILL);
+       switch_core_session_kill_channel(session, SWITCH_SIG_KILL);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status audio_bridge_on_ring(switch_core_session *session)
+{
+       switch_channel *channel = NULL;
+
+       channel = switch_core_session_get_channel(session);
+       assert(channel != NULL);
+
+       switch_console_printf(SWITCH_CHANNEL_CONSOLE, "CUSTOM RING\n");
+
+       /* put the channel in a passive state so we can loop audio to it */
+       if (switch_channel_test_flag(channel, CF_OUTBOUND)) {
+               switch_channel_set_state(channel, CS_TRANSMIT);
+               return SWITCH_STATUS_FALSE;
+       }
+
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
+static const switch_state_handler_table audio_bridge_peer_state_handlers = {
+       /*.on_init */ NULL,
+       /*.on_ring */ audio_bridge_on_ring,
+       /*.on_execute */ NULL,
+       /*.on_hangup */ audio_bridge_on_hangup,
+       /*.on_loopback */ NULL,
+       /*.on_transmit */ NULL
+};
+
+static const switch_state_handler_table audio_bridge_caller_state_handlers = {
+       /*.on_init */ NULL,
+       /*.on_ring */ NULL,
+       /*.on_execute */ NULL,
+       /*.on_hangup */ audio_bridge_on_hangup,
+       /*.on_loopback */ NULL,
+       /*.on_transmit */ NULL
+};
+
+SWITCH_DECLARE(switch_status) switch_ivr_multi_threaded_bridge(switch_core_session *session, 
+                                                                                                                          switch_core_session *peer_session,
+                                                                                                                          unsigned int timelimit)
+{
+       struct switch_core_thread_session this_audio_thread, other_audio_thread;
+       switch_channel *caller_channel, *peer_channel;
+       time_t start;
+       int stream_id = 0;
+
+       caller_channel = switch_core_session_get_channel(session);
+       assert(caller_channel != NULL);
+
+       peer_channel = switch_core_session_get_channel(peer_session);
+       assert(peer_channel != NULL);
+
+       memset(&other_audio_thread, 0, sizeof(other_audio_thread));
+       memset(&this_audio_thread, 0, sizeof(this_audio_thread));
+       other_audio_thread.objs[0] = session;
+       other_audio_thread.objs[1] = peer_session;
+       other_audio_thread.objs[2] = &stream_id;
+       other_audio_thread.running = 5;
+
+       this_audio_thread.objs[0] = peer_session;
+       this_audio_thread.objs[1] = session;
+       this_audio_thread.objs[2] = &stream_id;
+       this_audio_thread.running = 2;
+
+
+       switch_channel_set_private(caller_channel, peer_session);
+       switch_channel_set_private(peer_channel, session);
+       switch_channel_add_state_handler(caller_channel, &audio_bridge_caller_state_handlers);
+       switch_channel_add_state_handler(peer_channel, &audio_bridge_peer_state_handlers);
+       switch_core_session_thread_launch(peer_session);
+
+       for (;;) {
+               int state = switch_channel_get_state(peer_channel);
+               if (state > CS_RING) {
+                       break;
+               }
+               switch_yield(1000);
+       }
+
+       time(&start);
+       while (switch_channel_get_state(caller_channel) == CS_EXECUTE &&
+                  switch_channel_get_state(peer_channel) == CS_TRANSMIT &&
+                  !switch_channel_test_flag(peer_channel, CF_ANSWERED) &&
+                  !switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA) &&
+                  ((time(NULL) - start) < timelimit)) {
+               switch_yield(20000);
+       }
+
+       if (switch_channel_test_flag(peer_channel, CF_ANSWERED)) {
+               switch_channel_answer(caller_channel);
+       }
+
+       if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || 
+               switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) {
+
+               switch_core_session_launch_thread(session, audio_bridge_thread, (void *) &other_audio_thread);
+               audio_bridge_thread(NULL, (void *) &this_audio_thread);
+
+               switch_channel_hangup(peer_channel);
+               if (other_audio_thread.running > 0) {
+                       other_audio_thread.running = -1;
+                       /* wait for the other audio thread */
+                       while (other_audio_thread.running) {
+                               switch_yield(1000);
+                       }
+               }
+
+
+       }
+       return SWITCH_STATUS_SUCCESS;
+}