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: 195318 $")
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 ser = ast_tcptls_client_start(&ivr_desc);
00437
00438 if (!ser) {
00439 goto exit;
00440 }
00441 res = eivr_comm(chan, u, ser->fd, ser->fd, -1, pipe_delim_args, flags);
00442
00443 } else {
00444
00445 if (pipe(child_stdin)) {
00446 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
00447 goto exit;
00448 }
00449 if (pipe(child_stdout)) {
00450 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
00451 goto exit;
00452 }
00453 if (pipe(child_stderr)) {
00454 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
00455 goto exit;
00456 }
00457
00458 pid = ast_safe_fork(0);
00459 if (pid < 0) {
00460 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00461 goto exit;
00462 }
00463
00464 if (!pid) {
00465
00466 if (ast_opt_high_priority)
00467 ast_set_priority(0);
00468
00469 dup2(child_stdin[0], STDIN_FILENO);
00470 dup2(child_stdout[1], STDOUT_FILENO);
00471 dup2(child_stderr[1], STDERR_FILENO);
00472 ast_close_fds_above_n(STDERR_FILENO);
00473 execv(app_args[0], app_args);
00474 fprintf(stderr, "Failed to execute '%s': %s\n", app_args[0], strerror(errno));
00475 _exit(1);
00476 } else {
00477
00478 close(child_stdin[0]);
00479 child_stdin[0] = 0;
00480 close(child_stdout[1]);
00481 child_stdout[1] = 0;
00482 close(child_stderr[1]);
00483 child_stderr[1] = 0;
00484 res = eivr_comm(chan, u, child_stdin[1], child_stdout[0], child_stderr[0], pipe_delim_args, flags);
00485 }
00486 }
00487
00488 exit:
00489 if (u->gen_active)
00490 ast_deactivate_generator(chan);
00491
00492 if (child_stdin[0])
00493 close(child_stdin[0]);
00494
00495 if (child_stdin[1])
00496 close(child_stdin[1]);
00497
00498 if (child_stdout[0])
00499 close(child_stdout[0]);
00500
00501 if (child_stdout[1])
00502 close(child_stdout[1]);
00503
00504 if (child_stderr[0])
00505 close(child_stderr[0]);
00506
00507 if (child_stderr[1])
00508 close(child_stderr[1]);
00509 if (ser) {
00510 ao2_ref(ser, -1);
00511 }
00512 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
00513 ast_free(entry);
00514
00515 return res;
00516 }
00517
00518 static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
00519 int eivr_events_fd, int eivr_commands_fd, int eivr_errors_fd,
00520 const struct ast_str *args, const struct ast_flags flags)
00521 {
00522 struct playlist_entry *entry;
00523 struct ast_frame *f;
00524 int ms;
00525 int exception;
00526 int ready_fd;
00527 int waitfds[2] = { eivr_commands_fd, eivr_errors_fd };
00528 struct ast_channel *rchan;
00529 char *command;
00530 int res = -1;
00531 int test_available_fd = -1;
00532 int hangup_info_sent = 0;
00533
00534 FILE *eivr_commands = NULL;
00535 FILE *eivr_errors = NULL;
00536 FILE *eivr_events = NULL;
00537
00538 if (!(eivr_events = fdopen(eivr_events_fd, "w"))) {
00539 ast_chan_log(LOG_WARNING, chan, "Could not open stream to send events\n");
00540 goto exit;
00541 }
00542 if (!(eivr_commands = fdopen(eivr_commands_fd, "r"))) {
00543 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive commands\n");
00544 goto exit;
00545 }
00546 if (eivr_errors_fd > -1) {
00547 if (!(eivr_errors = fdopen(eivr_errors_fd, "r"))) {
00548 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive errors\n");
00549 goto exit;
00550 }
00551 }
00552
00553 test_available_fd = open("/dev/null", O_RDONLY);
00554
00555 setvbuf(eivr_events, NULL, _IONBF, 0);
00556 setvbuf(eivr_commands, NULL, _IONBF, 0);
00557 if (eivr_errors) {
00558 setvbuf(eivr_errors, NULL, _IONBF, 0);
00559 }
00560
00561 res = 0;
00562
00563 while (1) {
00564 if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
00565 ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
00566 res = -1;
00567 break;
00568 }
00569 if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) {
00570 if (ast_test_flag(&flags, ignore_hangup)) {
00571 ast_chan_log(LOG_NOTICE, chan, "Got check_hangup, but ignore_hangup set so sending 'I' command\n");
00572 send_eivr_event(eivr_events, 'I', "HANGUP", chan);
00573 hangup_info_sent = 1;
00574 } else {
00575 ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
00576 send_eivr_event(eivr_events, 'H', NULL, chan);
00577 res = -1;
00578 break;
00579 }
00580 }
00581
00582 ready_fd = 0;
00583 ms = 100;
00584 errno = 0;
00585 exception = 0;
00586
00587 rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd < 0) ? 1 : 2, &exception, &ready_fd, &ms);
00588
00589 if (chan->_state == AST_STATE_UP && !AST_LIST_EMPTY(&u->finishlist)) {
00590 AST_LIST_LOCK(&u->finishlist);
00591 while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
00592 send_eivr_event(eivr_events, 'F', entry->filename, chan);
00593 ast_free(entry);
00594 }
00595 AST_LIST_UNLOCK(&u->finishlist);
00596 }
00597
00598 if (chan->_state == AST_STATE_UP && !(ast_check_hangup(chan)) && rchan) {
00599
00600 f = ast_read(chan);
00601 if (!f) {
00602 ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
00603 send_eivr_event(eivr_events, 'H', NULL, chan);
00604 res = -1;
00605 break;
00606 }
00607 if (f->frametype == AST_FRAME_DTMF) {
00608 send_eivr_event(eivr_events, f->subclass, NULL, chan);
00609 if (u->option_autoclear) {
00610 if (!u->abort_current_sound && !u->playing_silence)
00611 send_eivr_event(eivr_events, 'T', NULL, chan);
00612 AST_LIST_LOCK(&u->playlist);
00613 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00614 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00615 ast_free(entry);
00616 }
00617 if (!u->playing_silence)
00618 u->abort_current_sound = 1;
00619 AST_LIST_UNLOCK(&u->playlist);
00620 }
00621 } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00622 ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
00623 send_eivr_event(eivr_events, 'H', NULL, chan);
00624 if (f->data.uint32) {
00625 chan->hangupcause = f->data.uint32;
00626 }
00627 ast_frfree(f);
00628 res = -1;
00629 break;
00630 }
00631 ast_frfree(f);
00632 } else if (ready_fd == eivr_commands_fd) {
00633 char input[1024];
00634
00635 if (exception || (dup2(eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) {
00636 ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00637 res = -1;
00638 break;
00639 }
00640
00641 if (!fgets(input, sizeof(input), eivr_commands))
00642 continue;
00643
00644 command = ast_strip(input);
00645
00646 if (option_debug)
00647 ast_debug(1, "got command '%s'\n", input);
00648
00649 if (strlen(input) < 4)
00650 continue;
00651
00652 if (input[0] == 'P') {
00653 send_eivr_event(eivr_events, 'P', args->str, chan);
00654 } else if ( input[0] == 'T' ) {
00655 ast_chan_log(LOG_WARNING, chan, "Answering channel if needed and starting generator\n");
00656 if (chan->_state != AST_STATE_UP) {
00657 if (ast_test_flag(&flags, run_dead)) {
00658 ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
00659 send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
00660 continue;
00661 }
00662 ast_answer(chan);
00663 }
00664 if (!(u->gen_active)) {
00665 if (ast_activate_generator(chan, &gen, u) < 0) {
00666 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
00667 send_eivr_event(eivr_events, 'Z', "GENERATOR_FAILURE", chan);
00668 } else {
00669 u->gen_active = 1;
00670 }
00671 }
00672 } else if (input[0] == 'S') {
00673 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00674 ast_chan_log(LOG_WARNING, chan, "Queue 'S'et called on unanswered channel\n");
00675 send_eivr_event(eivr_events, 'Z', NULL, chan);
00676 continue;
00677 }
00678 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00679 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00680 send_eivr_event(eivr_events, 'Z', NULL, chan);
00681 strcpy(&input[2], "exception");
00682 }
00683 if (!u->abort_current_sound && !u->playing_silence)
00684 send_eivr_event(eivr_events, 'T', NULL, chan);
00685 AST_LIST_LOCK(&u->playlist);
00686 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00687 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00688 ast_free(entry);
00689 }
00690 if (!u->playing_silence)
00691 u->abort_current_sound = 1;
00692 entry = make_entry(&input[2]);
00693 if (entry)
00694 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00695 AST_LIST_UNLOCK(&u->playlist);
00696 } else if (input[0] == 'A') {
00697 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00698 ast_chan_log(LOG_WARNING, chan, "Queue 'A'ppend called on unanswered channel\n");
00699 send_eivr_event(eivr_events, 'Z', NULL, chan);
00700 continue;
00701 }
00702 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00703 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00704 send_eivr_event(eivr_events, 'Z', NULL, chan);
00705 strcpy(&input[2], "exception");
00706 }
00707 entry = make_entry(&input[2]);
00708 if (entry) {
00709 AST_LIST_LOCK(&u->playlist);
00710 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00711 AST_LIST_UNLOCK(&u->playlist);
00712 }
00713 } else if (input[0] == 'G') {
00714
00715 char response[2048];
00716
00717 ast_chan_log(LOG_NOTICE, chan, "Getting a Variable out of the channel: %s\n", &input[2]);
00718 ast_eivr_getvariable(chan, &input[2], response, sizeof(response));
00719 send_eivr_event(eivr_events, 'G', response, chan);
00720 } else if (input[0] == 'V') {
00721
00722 ast_chan_log(LOG_NOTICE, chan, "Setting a Variable up: %s\n", &input[2]);
00723 ast_eivr_setvariable(chan, &input[2]);
00724 } else if (input[0] == 'L') {
00725 ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]);
00726 } else if (input[0] == 'X') {
00727 ast_chan_log(LOG_NOTICE, chan, "Exiting ExternalIVR: %s\n", &input[2]);
00728
00729 res = 0;
00730 break;
00731 } else if (input[0] == 'E') {
00732 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
00733 send_eivr_event(eivr_events, 'E', NULL, chan);
00734 res = 0;
00735 break;
00736 } else if (input[0] == 'H') {
00737 ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
00738 send_eivr_event(eivr_events, 'H', NULL, chan);
00739 res = -1;
00740 break;
00741 } else if (input[0] == 'O') {
00742 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00743 ast_chan_log(LOG_WARNING, chan, "Option called on unanswered channel\n");
00744 send_eivr_event(eivr_events, 'Z', NULL, chan);
00745 continue;
00746 }
00747 if (!strcasecmp(&input[2], "autoclear"))
00748 u->option_autoclear = 1;
00749 else if (!strcasecmp(&input[2], "noautoclear"))
00750 u->option_autoclear = 0;
00751 else
00752 ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
00753 }
00754 } else if (eivr_errors_fd && ready_fd == eivr_errors_fd) {
00755 char input[1024];
00756
00757 if (exception || feof(eivr_errors)) {
00758 ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00759 res = -1;
00760 break;
00761 }
00762 if (fgets(input, sizeof(input), eivr_errors)) {
00763 command = ast_strip(input);
00764 ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
00765 }
00766 } else if ((ready_fd < 0) && ms) {
00767 if (errno == 0 || errno == EINTR)
00768 continue;
00769
00770 ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
00771 break;
00772 }
00773 }
00774
00775
00776 exit:
00777
00778 if (test_available_fd > -1) {
00779 close(test_available_fd);
00780 }
00781
00782 if (eivr_events)
00783 fclose(eivr_events);
00784
00785 if (eivr_commands)
00786 fclose(eivr_commands);
00787
00788 if (eivr_errors)
00789 fclose(eivr_errors);
00790
00791 return res;
00792
00793 }
00794
00795 static int unload_module(void)
00796 {
00797 return ast_unregister_application(app);
00798 }
00799
00800 static int load_module(void)
00801 {
00802 return ast_register_application(app, app_exec, synopsis, descrip);
00803 }
00804
00805 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");