00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "asterisk.h"
00035
00036 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 225490 $")
00037
00038 #include <signal.h>
00039
00040 #include "asterisk/lock.h"
00041 #include "asterisk/file.h"
00042 #include "asterisk/channel.h"
00043 #include "asterisk/pbx.h"
00044 #include "asterisk/module.h"
00045 #include "asterisk/linkedlists.h"
00046 #include "asterisk/app.h"
00047 #include "asterisk/utils.h"
00048 #include "asterisk/tcptls.h"
00049 #include "asterisk/astobj2.h"
00050
00051 static const char *app = "ExternalIVR";
00052
00053 static const char *synopsis = "Interfaces with an external IVR application";
00054 static const char *descrip =
00055 " ExternalIVR(command|ivr://ivrhosti([,arg[,arg...]])[,options]): Either forks a process\n"
00056 "to run given command or makes a socket to connect to given host and starts\n"
00057 "a generator on the channel. The generator's play list is controlled by the\n"
00058 "external application, which can add and clear entries via simple commands\n"
00059 "issued over its stdout. The external application will receive all DTMF events\n"
00060 "received on the channel, and notification if the channel is hung up. The\n"
00061 "application will not be forcibly terminated when the channel is hung up.\n"
00062 "See doc/externalivr.txt for a protocol specification.\n"
00063 "The 'n' option tells ExternalIVR() not to answer the channel. \n"
00064 "The 'i' option tells ExternalIVR() not to send a hangup and exit when the\n"
00065 " channel receives a hangup, instead it sends an 'I' informative message\n"
00066 " meaning that the external application MUST hang up the call with an H command\n"
00067 "The 'd' option tells ExternalIVR() to run on a channel that has been hung up\n"
00068 " and will not look for hangups. The external application must exit with\n"
00069 " an 'E' command.\n";
00070
00071
00072 #define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__)
00073
00074 enum {
00075 noanswer = (1 << 0),
00076 ignore_hangup = (1 << 1),
00077 run_dead = (1 << 2),
00078 } options_flags;
00079
00080 AST_APP_OPTIONS(app_opts, {
00081 AST_APP_OPTION('n', noanswer),
00082 AST_APP_OPTION('i', ignore_hangup),
00083 AST_APP_OPTION('d', run_dead),
00084 });
00085
00086 struct playlist_entry {
00087 AST_LIST_ENTRY(playlist_entry) list;
00088 char filename[1];
00089 };
00090
00091 struct ivr_localuser {
00092 struct ast_channel *chan;
00093 AST_LIST_HEAD(playlist, playlist_entry) playlist;
00094 AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
00095 int abort_current_sound;
00096 int playing_silence;
00097 int option_autoclear;
00098 int gen_active;
00099 };
00100
00101
00102 struct gen_state {
00103 struct ivr_localuser *u;
00104 struct ast_filestream *stream;
00105 struct playlist_entry *current;
00106 int sample_queue;
00107 };
00108
00109 static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
00110 int eivr_events_fd, int eivr_commands_fd, int eivr_errors_fd,
00111 const struct ast_str *args, const struct ast_flags flags);
00112
00113 int eivr_connect_socket(struct ast_channel *chan, const char *host, int port);
00114
00115 static void send_eivr_event(FILE *handle, const char event, const char *data,
00116 const struct ast_channel *chan)
00117 {
00118 struct ast_str *tmp = ast_str_create(12);
00119
00120 ast_str_append(&tmp, 0, "%c,%10d", event, (int)time(NULL));
00121 if (data) {
00122 ast_str_append(&tmp, 0, ",%s", data);
00123 }
00124
00125 fprintf(handle, "%s\n", tmp->str);
00126 ast_debug(1, "sent '%s'\n", tmp->str);
00127 }
00128
00129 static void *gen_alloc(struct ast_channel *chan, void *params)
00130 {
00131 struct ivr_localuser *u = params;
00132 struct gen_state *state;
00133
00134 if (!(state = ast_calloc(1, sizeof(*state))))
00135 return NULL;
00136
00137 state->u = u;
00138
00139 return state;
00140 }
00141
00142 static void gen_closestream(struct gen_state *state)
00143 {
00144 if (!state->stream)
00145 return;
00146
00147 ast_closestream(state->stream);
00148 state->u->chan->stream = NULL;
00149 state->stream = NULL;
00150 }
00151
00152 static void gen_release(struct ast_channel *chan, void *data)
00153 {
00154 struct gen_state *state = data;
00155
00156 gen_closestream(state);
00157 ast_free(data);
00158 }
00159
00160
00161 static int gen_nextfile(struct gen_state *state)
00162 {
00163 struct ivr_localuser *u = state->u;
00164 char *file_to_stream;
00165
00166 u->abort_current_sound = 0;
00167 u->playing_silence = 0;
00168 gen_closestream(state);
00169
00170 while (!state->stream) {
00171 state->current = AST_LIST_REMOVE_HEAD(&u->playlist, list);
00172 if (state->current) {
00173 file_to_stream = state->current->filename;
00174 } else {
00175 file_to_stream = "silence/10";
00176 u->playing_silence = 1;
00177 }
00178
00179 if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) {
00180 ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
00181 if (!u->playing_silence) {
00182 continue;
00183 } else {
00184 break;
00185 }
00186 }
00187 }
00188
00189 return (!state->stream);
00190 }
00191
00192 static struct ast_frame *gen_readframe(struct gen_state *state)
00193 {
00194 struct ast_frame *f = NULL;
00195 struct ivr_localuser *u = state->u;
00196
00197 if (u->abort_current_sound ||
00198 (u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
00199 gen_closestream(state);
00200 AST_LIST_LOCK(&u->playlist);
00201 gen_nextfile(state);
00202 AST_LIST_UNLOCK(&u->playlist);
00203 }
00204
00205 if (!(state->stream && (f = ast_readframe(state->stream)))) {
00206 if (state->current) {
00207 AST_LIST_LOCK(&u->finishlist);
00208 AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
00209 AST_LIST_UNLOCK(&u->finishlist);
00210 state->current = NULL;
00211 }
00212 if (!gen_nextfile(state))
00213 f = ast_readframe(state->stream);
00214 }
00215
00216 return f;
00217 }
00218
00219 static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)
00220 {
00221 struct gen_state *state = data;
00222 struct ast_frame *f = NULL;
00223 int res = 0;
00224
00225 state->sample_queue += samples;
00226
00227 while (state->sample_queue > 0) {
00228 if (!(f = gen_readframe(state)))
00229 return -1;
00230
00231 res = ast_write(chan, f);
00232 ast_frfree(f);
00233 if (res < 0) {
00234 ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
00235 return -1;
00236 }
00237 state->sample_queue -= f->samples;
00238 }
00239
00240 return res;
00241 }
00242
00243 static struct ast_generator gen =
00244 {
00245 alloc: gen_alloc,
00246 release: gen_release,
00247 generate: gen_generate,
00248 };
00249
00250 static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
00251 {
00252
00253
00254
00255 char *inbuf, *variable;
00256 const char *value;
00257 int j;
00258 struct ast_str *newstring = ast_str_alloca(outbuflen);
00259
00260 outbuf[0] = '\0';
00261
00262 for (j = 1, inbuf = data; ; j++) {
00263 variable = strsep(&inbuf, ",");
00264 if (variable == NULL) {
00265 int outstrlen = strlen(outbuf);
00266 if (outstrlen && outbuf[outstrlen - 1] == ',') {
00267 outbuf[outstrlen - 1] = 0;
00268 }
00269 break;
00270 }
00271
00272 ast_channel_lock(chan);
00273 if (!(value = pbx_builtin_getvar_helper(chan, variable))) {
00274 value = "";
00275 }
00276
00277 ast_str_append(&newstring, 0, "%s=%s,", variable, value);
00278 ast_channel_unlock(chan);
00279 ast_copy_string(outbuf, newstring->str, outbuflen);
00280 }
00281 }
00282
00283 static void ast_eivr_setvariable(struct ast_channel *chan, char *data)
00284 {
00285 char *value;
00286
00287 char *inbuf = ast_strdupa(data), *variable;
00288
00289 for (variable = strsep(&inbuf, ","); variable; variable = strsep(&inbuf, ",")) {
00290 ast_debug(1, "Setting up a variable: %s\n", variable);
00291
00292 value = strchr(variable, '=');
00293 if (!value) {
00294 value = "";
00295 } else {
00296 *value++ = '\0';
00297 }
00298 pbx_builtin_setvar_helper(chan, variable, value);
00299 }
00300 }
00301
00302 static struct playlist_entry *make_entry(const char *filename)
00303 {
00304 struct playlist_entry *entry;
00305
00306 if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10)))
00307 return NULL;
00308
00309 strcpy(entry->filename, filename);
00310
00311 return entry;
00312 }
00313
00314 static int app_exec(struct ast_channel *chan, void *data)
00315 {
00316 struct ast_flags flags = { 0, };
00317 char *opts[0];
00318 struct playlist_entry *entry;
00319 int child_stdin[2] = { 0, 0 };
00320 int child_stdout[2] = { 0, 0 };
00321 int child_stderr[2] = { 0, 0 };
00322 int res = -1;
00323 int pid;
00324
00325 char hostname[1024];
00326 char *port_str = NULL;
00327 int port = 0;
00328 struct ast_tcptls_session_instance *ser = NULL;
00329
00330 struct ivr_localuser foo = {
00331 .playlist = AST_LIST_HEAD_INIT_VALUE,
00332 .finishlist = AST_LIST_HEAD_INIT_VALUE,
00333 .gen_active = 0,
00334 };
00335 struct ivr_localuser *u = &foo;
00336
00337 char *buf;
00338 int j;
00339 char *s, **app_args, *e;
00340 struct ast_str *pipe_delim_args = ast_str_create(100);
00341
00342 AST_DECLARE_APP_ARGS(eivr_args,
00343 AST_APP_ARG(cmd)[32];
00344 );
00345 AST_DECLARE_APP_ARGS(application_args,
00346 AST_APP_ARG(cmd)[32];
00347 );
00348
00349 u->abort_current_sound = 0;
00350 u->chan = chan;
00351
00352 buf = ast_strdupa(data);
00353 AST_STANDARD_APP_ARGS(eivr_args, buf);
00354
00355 if ((s = strchr(eivr_args.cmd[0], '('))) {
00356 s[0] = ',';
00357 if (( e = strrchr(s, ')')) ) {
00358 *e = '\0';
00359 } else {
00360 ast_log(LOG_ERROR, "Parse error, no closing paren?\n");
00361 }
00362 AST_STANDARD_APP_ARGS(application_args, eivr_args.cmd[0]);
00363 app_args = application_args.argv;
00364
00365
00366 ast_str_reset(pipe_delim_args);
00367 for (j = 0; application_args.cmd[j] != NULL; j++) {
00368 ast_str_append(&pipe_delim_args, 0, "%s%s", j == 0 ? "" : ",", application_args.cmd[j]);
00369 }
00370
00371
00372 if (option_debug)
00373 ast_debug(1, "Parsing options from: [%s]\n", eivr_args.cmd[1]);
00374 ast_app_parse_options(app_opts, &flags, opts, eivr_args.cmd[1]);
00375 if (option_debug) {
00376 if (ast_test_flag(&flags, noanswer))
00377 ast_debug(1, "noanswer is set\n");
00378 if (ast_test_flag(&flags, ignore_hangup))
00379 ast_debug(1, "ignore_hangup is set\n");
00380 if (ast_test_flag(&flags, run_dead))
00381 ast_debug(1, "run_dead is set\n");
00382 }
00383
00384 } else {
00385 app_args = eivr_args.argv;
00386 for (j = 0; eivr_args.cmd[j] != NULL; j++) {
00387 ast_str_append(&pipe_delim_args, 0, "%s%s", j == 0 ? "" : "|", eivr_args.cmd[j]);
00388 }
00389 }
00390
00391 if (ast_strlen_zero(data)) {
00392 ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
00393 return -1;
00394 }
00395
00396 if (!(ast_test_flag(&flags, noanswer))) {
00397 ast_chan_log(LOG_WARNING, chan, "Answering channel and starting generator\n");
00398 if (chan->_state != AST_STATE_UP) {
00399 if (ast_test_flag(&flags, run_dead)) {
00400 ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
00401 goto exit;
00402 }
00403 ast_answer(chan);
00404 }
00405 if (ast_activate_generator(chan, &gen, u) < 0) {
00406 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
00407 goto exit;
00408 } else {
00409 u->gen_active = 1;
00410 }
00411 }
00412
00413 if (!strncmp(app_args[0], "ivr://", 6)) {
00414 struct ast_tcptls_session_args ivr_desc = {
00415 .accept_fd = -1,
00416 .name = "IVR",
00417 };
00418 struct ast_hostent hp;
00419
00420
00421 ast_debug(1, "Parsing hostname:port for socket connect from \"%s\"\n", app_args[0]);
00422 ast_copy_string(hostname, app_args[0] + 6, sizeof(hostname));
00423 if ((port_str = strchr(hostname, ':')) != NULL) {
00424 port_str[0] = 0;
00425 port_str += 1;
00426 port = atoi(port_str);
00427 }
00428 if (!port) {
00429 port = 2949;
00430 }
00431
00432 ast_gethostbyname(hostname, &hp);
00433 ivr_desc.local_address.sin_family = AF_INET;
00434 ivr_desc.local_address.sin_port = htons(port);
00435 memcpy(&ivr_desc.local_address.sin_addr.s_addr, hp.hp.h_addr, hp.hp.h_length);
00436 if (!(ser = ast_tcptls_client_create(&ivr_desc)) || !(ser = ast_tcptls_client_start(ser))) {
00437 goto exit;
00438 }
00439 res = eivr_comm(chan, u, ser->fd, ser->fd, -1, pipe_delim_args, flags);
00440
00441 } else {
00442
00443 if (pipe(child_stdin)) {
00444 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
00445 goto exit;
00446 }
00447 if (pipe(child_stdout)) {
00448 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
00449 goto exit;
00450 }
00451 if (pipe(child_stderr)) {
00452 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
00453 goto exit;
00454 }
00455
00456 pid = ast_safe_fork(0);
00457 if (pid < 0) {
00458 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00459 goto exit;
00460 }
00461
00462 if (!pid) {
00463
00464 if (ast_opt_high_priority)
00465 ast_set_priority(0);
00466
00467 dup2(child_stdin[0], STDIN_FILENO);
00468 dup2(child_stdout[1], STDOUT_FILENO);
00469 dup2(child_stderr[1], STDERR_FILENO);
00470 ast_close_fds_above_n(STDERR_FILENO);
00471 execv(app_args[0], app_args);
00472 fprintf(stderr, "Failed to execute '%s': %s\n", app_args[0], strerror(errno));
00473 _exit(1);
00474 } else {
00475
00476 close(child_stdin[0]);
00477 child_stdin[0] = 0;
00478 close(child_stdout[1]);
00479 child_stdout[1] = 0;
00480 close(child_stderr[1]);
00481 child_stderr[1] = 0;
00482 res = eivr_comm(chan, u, child_stdin[1], child_stdout[0], child_stderr[0], pipe_delim_args, flags);
00483 }
00484 }
00485
00486 exit:
00487 if (u->gen_active)
00488 ast_deactivate_generator(chan);
00489
00490 if (child_stdin[0])
00491 close(child_stdin[0]);
00492
00493 if (child_stdin[1])
00494 close(child_stdin[1]);
00495
00496 if (child_stdout[0])
00497 close(child_stdout[0]);
00498
00499 if (child_stdout[1])
00500 close(child_stdout[1]);
00501
00502 if (child_stderr[0])
00503 close(child_stderr[0]);
00504
00505 if (child_stderr[1])
00506 close(child_stderr[1]);
00507 if (ser) {
00508 ao2_ref(ser, -1);
00509 }
00510 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
00511 ast_free(entry);
00512
00513 return res;
00514 }
00515
00516 static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
00517 int eivr_events_fd, int eivr_commands_fd, int eivr_errors_fd,
00518 const struct ast_str *args, const struct ast_flags flags)
00519 {
00520 struct playlist_entry *entry;
00521 struct ast_frame *f;
00522 int ms;
00523 int exception;
00524 int ready_fd;
00525 int waitfds[2] = { eivr_commands_fd, eivr_errors_fd };
00526 struct ast_channel *rchan;
00527 char *command;
00528 int res = -1;
00529 int test_available_fd = -1;
00530 int hangup_info_sent = 0;
00531
00532 FILE *eivr_commands = NULL;
00533 FILE *eivr_errors = NULL;
00534 FILE *eivr_events = NULL;
00535
00536 if (!(eivr_events = fdopen(eivr_events_fd, "w"))) {
00537 ast_chan_log(LOG_WARNING, chan, "Could not open stream to send events\n");
00538 goto exit;
00539 }
00540 if (!(eivr_commands = fdopen(eivr_commands_fd, "r"))) {
00541 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive commands\n");
00542 goto exit;
00543 }
00544 if (eivr_errors_fd > -1) {
00545 if (!(eivr_errors = fdopen(eivr_errors_fd, "r"))) {
00546 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive errors\n");
00547 goto exit;
00548 }
00549 }
00550
00551 test_available_fd = open("/dev/null", O_RDONLY);
00552
00553 setvbuf(eivr_events, NULL, _IONBF, 0);
00554 setvbuf(eivr_commands, NULL, _IONBF, 0);
00555 if (eivr_errors) {
00556 setvbuf(eivr_errors, NULL, _IONBF, 0);
00557 }
00558
00559 res = 0;
00560
00561 while (1) {
00562 if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
00563 ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
00564 res = -1;
00565 break;
00566 }
00567 if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) {
00568 if (ast_test_flag(&flags, ignore_hangup)) {
00569 ast_chan_log(LOG_NOTICE, chan, "Got check_hangup, but ignore_hangup set so sending 'I' command\n");
00570 send_eivr_event(eivr_events, 'I', "HANGUP", chan);
00571 hangup_info_sent = 1;
00572 } else {
00573 ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
00574 send_eivr_event(eivr_events, 'H', NULL, chan);
00575 res = -1;
00576 break;
00577 }
00578 }
00579
00580 ready_fd = 0;
00581 ms = 100;
00582 errno = 0;
00583 exception = 0;
00584
00585 rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd < 0) ? 1 : 2, &exception, &ready_fd, &ms);
00586
00587 if (chan->_state == AST_STATE_UP && !AST_LIST_EMPTY(&u->finishlist)) {
00588 AST_LIST_LOCK(&u->finishlist);
00589 while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
00590 send_eivr_event(eivr_events, 'F', entry->filename, chan);
00591 ast_free(entry);
00592 }
00593 AST_LIST_UNLOCK(&u->finishlist);
00594 }
00595
00596 if (chan->_state == AST_STATE_UP && !(ast_check_hangup(chan)) && rchan) {
00597
00598 f = ast_read(chan);
00599 if (!f) {
00600 ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
00601 send_eivr_event(eivr_events, 'H', NULL, chan);
00602 res = -1;
00603 break;
00604 }
00605 if (f->frametype == AST_FRAME_DTMF) {
00606 send_eivr_event(eivr_events, f->subclass, NULL, chan);
00607 if (u->option_autoclear) {
00608 if (!u->abort_current_sound && !u->playing_silence)
00609 send_eivr_event(eivr_events, 'T', NULL, chan);
00610 AST_LIST_LOCK(&u->playlist);
00611 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00612 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00613 ast_free(entry);
00614 }
00615 if (!u->playing_silence)
00616 u->abort_current_sound = 1;
00617 AST_LIST_UNLOCK(&u->playlist);
00618 }
00619 } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00620 ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
00621 send_eivr_event(eivr_events, 'H', NULL, chan);
00622 if (f->data.uint32) {
00623 chan->hangupcause = f->data.uint32;
00624 }
00625 ast_frfree(f);
00626 res = -1;
00627 break;
00628 }
00629 ast_frfree(f);
00630 } else if (ready_fd == eivr_commands_fd) {
00631 char input[1024];
00632
00633 if (exception || (dup2(eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) {
00634 ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00635 res = -1;
00636 break;
00637 }
00638
00639 if (!fgets(input, sizeof(input), eivr_commands))
00640 continue;
00641
00642 command = ast_strip(input);
00643
00644 if (option_debug)
00645 ast_debug(1, "got command '%s'\n", input);
00646
00647 if (strlen(input) < 4)
00648 continue;
00649
00650 if (input[0] == 'P') {
00651 send_eivr_event(eivr_events, 'P', args->str, chan);
00652 } else if ( input[0] == 'T' ) {
00653 ast_chan_log(LOG_WARNING, chan, "Answering channel if needed and starting generator\n");
00654 if (chan->_state != AST_STATE_UP) {
00655 if (ast_test_flag(&flags, run_dead)) {
00656 ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
00657 send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
00658 continue;
00659 }
00660 ast_answer(chan);
00661 }
00662 if (!(u->gen_active)) {
00663 if (ast_activate_generator(chan, &gen, u) < 0) {
00664 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
00665 send_eivr_event(eivr_events, 'Z', "GENERATOR_FAILURE", chan);
00666 } else {
00667 u->gen_active = 1;
00668 }
00669 }
00670 } else if (input[0] == 'S') {
00671 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00672 ast_chan_log(LOG_WARNING, chan, "Queue 'S'et called on unanswered channel\n");
00673 send_eivr_event(eivr_events, 'Z', NULL, chan);
00674 continue;
00675 }
00676 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00677 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00678 send_eivr_event(eivr_events, 'Z', NULL, chan);
00679 strcpy(&input[2], "exception");
00680 }
00681 if (!u->abort_current_sound && !u->playing_silence)
00682 send_eivr_event(eivr_events, 'T', NULL, chan);
00683 AST_LIST_LOCK(&u->playlist);
00684 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00685 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00686 ast_free(entry);
00687 }
00688 if (!u->playing_silence)
00689 u->abort_current_sound = 1;
00690 entry = make_entry(&input[2]);
00691 if (entry)
00692 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00693 AST_LIST_UNLOCK(&u->playlist);
00694 } else if (input[0] == 'A') {
00695 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00696 ast_chan_log(LOG_WARNING, chan, "Queue 'A'ppend called on unanswered channel\n");
00697 send_eivr_event(eivr_events, 'Z', NULL, chan);
00698 continue;
00699 }
00700 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00701 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00702 send_eivr_event(eivr_events, 'Z', NULL, chan);
00703 strcpy(&input[2], "exception");
00704 }
00705 entry = make_entry(&input[2]);
00706 if (entry) {
00707 AST_LIST_LOCK(&u->playlist);
00708 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00709 AST_LIST_UNLOCK(&u->playlist);
00710 }
00711 } else if (input[0] == 'G') {
00712
00713 char response[2048];
00714
00715 ast_chan_log(LOG_NOTICE, chan, "Getting a Variable out of the channel: %s\n", &input[2]);
00716 ast_eivr_getvariable(chan, &input[2], response, sizeof(response));
00717 send_eivr_event(eivr_events, 'G', response, chan);
00718 } else if (input[0] == 'V') {
00719
00720 ast_chan_log(LOG_NOTICE, chan, "Setting a Variable up: %s\n", &input[2]);
00721 ast_eivr_setvariable(chan, &input[2]);
00722 } else if (input[0] == 'L') {
00723 ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]);
00724 } else if (input[0] == 'X') {
00725 ast_chan_log(LOG_NOTICE, chan, "Exiting ExternalIVR: %s\n", &input[2]);
00726
00727 res = 0;
00728 break;
00729 } else if (input[0] == 'E') {
00730 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
00731 send_eivr_event(eivr_events, 'E', NULL, chan);
00732 res = 0;
00733 break;
00734 } else if (input[0] == 'H') {
00735 ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
00736 send_eivr_event(eivr_events, 'H', NULL, chan);
00737 res = -1;
00738 break;
00739 } else if (input[0] == 'O') {
00740 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00741 ast_chan_log(LOG_WARNING, chan, "Option called on unanswered channel\n");
00742 send_eivr_event(eivr_events, 'Z', NULL, chan);
00743 continue;
00744 }
00745 if (!strcasecmp(&input[2], "autoclear"))
00746 u->option_autoclear = 1;
00747 else if (!strcasecmp(&input[2], "noautoclear"))
00748 u->option_autoclear = 0;
00749 else
00750 ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
00751 }
00752 } else if (eivr_errors_fd && ready_fd == eivr_errors_fd) {
00753 char input[1024];
00754
00755 if (exception || feof(eivr_errors)) {
00756 ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00757 res = -1;
00758 break;
00759 }
00760 if (fgets(input, sizeof(input), eivr_errors)) {
00761 command = ast_strip(input);
00762 ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
00763 }
00764 } else if ((ready_fd < 0) && ms) {
00765 if (errno == 0 || errno == EINTR)
00766 continue;
00767
00768 ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
00769 break;
00770 }
00771 }
00772
00773
00774 exit:
00775
00776 if (test_available_fd > -1) {
00777 close(test_available_fd);
00778 }
00779
00780 if (eivr_events)
00781 fclose(eivr_events);
00782
00783 if (eivr_commands)
00784 fclose(eivr_commands);
00785
00786 if (eivr_errors)
00787 fclose(eivr_errors);
00788
00789 return res;
00790
00791 }
00792
00793 static int unload_module(void)
00794 {
00795 return ast_unregister_application(app);
00796 }
00797
00798 static int load_module(void)
00799 {
00800 return ast_register_application(app, app_exec, synopsis, descrip);
00801 }
00802
00803 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");