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: 174330 $")
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 buf[1024];
00286 char *value;
00287
00288 char *inbuf, *variable;
00289
00290 int j;
00291
00292 for (j = 1, inbuf = data; ; j++, inbuf = NULL) {
00293 variable = strsep(&inbuf, ",");
00294 ast_debug(1, "Setting up a variable: %s\n", variable);
00295 if (variable) {
00296
00297 ast_copy_string(buf, variable, sizeof(buf));
00298 value = strchr(buf, '=');
00299 if (!value) {
00300 value = "";
00301 } else {
00302 *value++ = '\0';
00303 }
00304 pbx_builtin_setvar_helper(chan, buf, value);
00305 } else {
00306 break;
00307 }
00308 }
00309 }
00310
00311 static struct playlist_entry *make_entry(const char *filename)
00312 {
00313 struct playlist_entry *entry;
00314
00315 if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10)))
00316 return NULL;
00317
00318 strcpy(entry->filename, filename);
00319
00320 return entry;
00321 }
00322
00323 static int app_exec(struct ast_channel *chan, void *data)
00324 {
00325 struct ast_flags flags = { 0, };
00326 char *opts[0];
00327 struct playlist_entry *entry;
00328 int child_stdin[2] = { 0, 0 };
00329 int child_stdout[2] = { 0, 0 };
00330 int child_stderr[2] = { 0, 0 };
00331 int res = -1;
00332 int pid;
00333
00334 char hostname[1024];
00335 char *port_str = NULL;
00336 int port = 0;
00337 struct ast_tcptls_session_instance *ser = NULL;
00338
00339 struct ivr_localuser foo = {
00340 .playlist = AST_LIST_HEAD_INIT_VALUE,
00341 .finishlist = AST_LIST_HEAD_INIT_VALUE,
00342 .gen_active = 0,
00343 };
00344 struct ivr_localuser *u = &foo;
00345
00346 char *buf;
00347 int j;
00348 char *s, **app_args, *e;
00349 struct ast_str *pipe_delim_args = ast_str_create(100);
00350
00351 AST_DECLARE_APP_ARGS(eivr_args,
00352 AST_APP_ARG(cmd)[32];
00353 );
00354 AST_DECLARE_APP_ARGS(application_args,
00355 AST_APP_ARG(cmd)[32];
00356 );
00357
00358 u->abort_current_sound = 0;
00359 u->chan = chan;
00360
00361 buf = ast_strdupa(data);
00362 AST_STANDARD_APP_ARGS(eivr_args, buf);
00363
00364 if ((s = strchr(eivr_args.cmd[0], '('))) {
00365 s[0] = ',';
00366 if (( e = strrchr(s, ')')) ) {
00367 *e = '\0';
00368 } else {
00369 ast_log(LOG_ERROR, "Parse error, no closing paren?\n");
00370 }
00371 AST_STANDARD_APP_ARGS(application_args, eivr_args.cmd[0]);
00372 app_args = application_args.argv;
00373
00374
00375 ast_str_reset(pipe_delim_args);
00376 for (j = 0; application_args.cmd[j] != NULL; j++) {
00377 ast_str_append(&pipe_delim_args, 0, "%s%s", j == 0 ? "" : ",", application_args.cmd[j]);
00378 }
00379
00380
00381 if (option_debug)
00382 ast_debug(1, "Parsing options from: [%s]\n", eivr_args.cmd[1]);
00383 ast_app_parse_options(app_opts, &flags, opts, eivr_args.cmd[1]);
00384 if (option_debug) {
00385 if (ast_test_flag(&flags, noanswer))
00386 ast_debug(1, "noanswer is set\n");
00387 if (ast_test_flag(&flags, ignore_hangup))
00388 ast_debug(1, "ignore_hangup is set\n");
00389 if (ast_test_flag(&flags, run_dead))
00390 ast_debug(1, "run_dead is set\n");
00391 }
00392
00393 } else {
00394 app_args = eivr_args.argv;
00395 for (j = 0; eivr_args.cmd[j] != NULL; j++) {
00396 ast_str_append(&pipe_delim_args, 0, "%s%s", j == 0 ? "" : "|", eivr_args.cmd[j]);
00397 }
00398 }
00399
00400 if (ast_strlen_zero(data)) {
00401 ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
00402 return -1;
00403 }
00404
00405 if (!(ast_test_flag(&flags, noanswer))) {
00406 ast_chan_log(LOG_WARNING, chan, "Answering channel and starting generator\n");
00407 if (chan->_state != AST_STATE_UP) {
00408 if (ast_test_flag(&flags, run_dead)) {
00409 ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
00410 goto exit;
00411 }
00412 ast_answer(chan);
00413 }
00414 if (ast_activate_generator(chan, &gen, u) < 0) {
00415 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
00416 goto exit;
00417 } else {
00418 u->gen_active = 1;
00419 }
00420 }
00421
00422 if (!strncmp(app_args[0], "ivr://", 6)) {
00423 struct ast_tcptls_session_args ivr_desc = {
00424 .accept_fd = -1,
00425 .name = "IVR",
00426 };
00427 struct ast_hostent hp;
00428
00429
00430 ast_debug(1, "Parsing hostname:port for socket connect from \"%s\"\n", app_args[0]);
00431 ast_copy_string(hostname, app_args[0] + 6, sizeof(hostname));
00432 if ((port_str = strchr(hostname, ':')) != NULL) {
00433 port_str[0] = 0;
00434 port_str += 1;
00435 port = atoi(port_str);
00436 }
00437 if (!port) {
00438 port = 2949;
00439 }
00440
00441 ast_gethostbyname(hostname, &hp);
00442 ivr_desc.local_address.sin_family = AF_INET;
00443 ivr_desc.local_address.sin_port = htons(port);
00444 memcpy(&ivr_desc.local_address.sin_addr.s_addr, hp.hp.h_addr, hp.hp.h_length);
00445 ser = ast_tcptls_client_start(&ivr_desc);
00446
00447 if (!ser) {
00448 goto exit;
00449 }
00450 res = eivr_comm(chan, u, ser->fd, ser->fd, -1, pipe_delim_args, flags);
00451
00452 } else {
00453
00454 if (pipe(child_stdin)) {
00455 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
00456 goto exit;
00457 }
00458 if (pipe(child_stdout)) {
00459 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
00460 goto exit;
00461 }
00462 if (pipe(child_stderr)) {
00463 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
00464 goto exit;
00465 }
00466
00467 pid = ast_safe_fork(0);
00468 if (pid < 0) {
00469 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00470 goto exit;
00471 }
00472
00473 if (!pid) {
00474
00475 if (ast_opt_high_priority)
00476 ast_set_priority(0);
00477
00478 dup2(child_stdin[0], STDIN_FILENO);
00479 dup2(child_stdout[1], STDOUT_FILENO);
00480 dup2(child_stderr[1], STDERR_FILENO);
00481 ast_close_fds_above_n(STDERR_FILENO);
00482 execv(app_args[0], app_args);
00483 fprintf(stderr, "Failed to execute '%s': %s\n", app_args[0], strerror(errno));
00484 _exit(1);
00485 } else {
00486
00487 close(child_stdin[0]);
00488 child_stdin[0] = 0;
00489 close(child_stdout[1]);
00490 child_stdout[1] = 0;
00491 close(child_stderr[1]);
00492 child_stderr[1] = 0;
00493 res = eivr_comm(chan, u, child_stdin[1], child_stdout[0], child_stderr[0], pipe_delim_args, flags);
00494 }
00495 }
00496
00497 exit:
00498 if (u->gen_active)
00499 ast_deactivate_generator(chan);
00500
00501 if (child_stdin[0])
00502 close(child_stdin[0]);
00503
00504 if (child_stdin[1])
00505 close(child_stdin[1]);
00506
00507 if (child_stdout[0])
00508 close(child_stdout[0]);
00509
00510 if (child_stdout[1])
00511 close(child_stdout[1]);
00512
00513 if (child_stderr[0])
00514 close(child_stderr[0]);
00515
00516 if (child_stderr[1])
00517 close(child_stderr[1]);
00518 if (ser) {
00519 ao2_ref(ser, -1);
00520 }
00521 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
00522 ast_free(entry);
00523
00524 return res;
00525 }
00526
00527 static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
00528 int eivr_events_fd, int eivr_commands_fd, int eivr_errors_fd,
00529 const struct ast_str *args, const struct ast_flags flags)
00530 {
00531 struct playlist_entry *entry;
00532 struct ast_frame *f;
00533 int ms;
00534 int exception;
00535 int ready_fd;
00536 int waitfds[2] = { eivr_commands_fd, eivr_errors_fd };
00537 struct ast_channel *rchan;
00538 char *command;
00539 int res = -1;
00540 int test_available_fd = -1;
00541 int hangup_info_sent = 0;
00542
00543 FILE *eivr_commands = NULL;
00544 FILE *eivr_errors = NULL;
00545 FILE *eivr_events = NULL;
00546
00547 if (!(eivr_events = fdopen(eivr_events_fd, "w"))) {
00548 ast_chan_log(LOG_WARNING, chan, "Could not open stream to send events\n");
00549 goto exit;
00550 }
00551 if (!(eivr_commands = fdopen(eivr_commands_fd, "r"))) {
00552 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive commands\n");
00553 goto exit;
00554 }
00555 if (eivr_errors_fd > -1) {
00556 if (!(eivr_errors = fdopen(eivr_errors_fd, "r"))) {
00557 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive errors\n");
00558 goto exit;
00559 }
00560 }
00561
00562 test_available_fd = open("/dev/null", O_RDONLY);
00563
00564 setvbuf(eivr_events, NULL, _IONBF, 0);
00565 setvbuf(eivr_commands, NULL, _IONBF, 0);
00566 if (eivr_errors) {
00567 setvbuf(eivr_errors, NULL, _IONBF, 0);
00568 }
00569
00570 res = 0;
00571
00572 while (1) {
00573 if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
00574 ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
00575 res = -1;
00576 break;
00577 }
00578 if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) {
00579 if (ast_test_flag(&flags, ignore_hangup)) {
00580 ast_chan_log(LOG_NOTICE, chan, "Got check_hangup, but ignore_hangup set so sending 'I' command\n");
00581 send_eivr_event(eivr_events, 'I', "HANGUP", chan);
00582 hangup_info_sent = 1;
00583 } else {
00584 ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
00585 send_eivr_event(eivr_events, 'H', NULL, chan);
00586 res = -1;
00587 break;
00588 }
00589 }
00590
00591 ready_fd = 0;
00592 ms = 100;
00593 errno = 0;
00594 exception = 0;
00595
00596 rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd < 0) ? 1 : 2, &exception, &ready_fd, &ms);
00597
00598 if (chan->_state == AST_STATE_UP && !AST_LIST_EMPTY(&u->finishlist)) {
00599 AST_LIST_LOCK(&u->finishlist);
00600 while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
00601 send_eivr_event(eivr_events, 'F', entry->filename, chan);
00602 ast_free(entry);
00603 }
00604 AST_LIST_UNLOCK(&u->finishlist);
00605 }
00606
00607 if (chan->_state == AST_STATE_UP && !(ast_check_hangup(chan)) && rchan) {
00608
00609 f = ast_read(chan);
00610 if (!f) {
00611 ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
00612 send_eivr_event(eivr_events, 'H', NULL, chan);
00613 res = -1;
00614 break;
00615 }
00616 if (f->frametype == AST_FRAME_DTMF) {
00617 send_eivr_event(eivr_events, f->subclass, NULL, chan);
00618 if (u->option_autoclear) {
00619 if (!u->abort_current_sound && !u->playing_silence)
00620 send_eivr_event(eivr_events, 'T', NULL, chan);
00621 AST_LIST_LOCK(&u->playlist);
00622 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00623 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00624 ast_free(entry);
00625 }
00626 if (!u->playing_silence)
00627 u->abort_current_sound = 1;
00628 AST_LIST_UNLOCK(&u->playlist);
00629 }
00630 } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00631 ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
00632 send_eivr_event(eivr_events, 'H', NULL, chan);
00633 if (f->data.uint32) {
00634 chan->hangupcause = f->data.uint32;
00635 }
00636 ast_frfree(f);
00637 res = -1;
00638 break;
00639 }
00640 ast_frfree(f);
00641 } else if (ready_fd == eivr_commands_fd) {
00642 char input[1024];
00643
00644 if (exception || (dup2(eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) {
00645 ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00646 res = -1;
00647 break;
00648 }
00649
00650 if (!fgets(input, sizeof(input), eivr_commands))
00651 continue;
00652
00653 command = ast_strip(input);
00654
00655 if (option_debug)
00656 ast_debug(1, "got command '%s'\n", input);
00657
00658 if (strlen(input) < 4)
00659 continue;
00660
00661 if (input[0] == 'P') {
00662 send_eivr_event(eivr_events, 'P', args->str, chan);
00663 } else if ( input[0] == 'T' ) {
00664 ast_chan_log(LOG_WARNING, chan, "Answering channel if needed and starting generator\n");
00665 if (chan->_state != AST_STATE_UP) {
00666 if (ast_test_flag(&flags, run_dead)) {
00667 ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
00668 send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
00669 continue;
00670 }
00671 ast_answer(chan);
00672 }
00673 if (!(u->gen_active)) {
00674 if (ast_activate_generator(chan, &gen, u) < 0) {
00675 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
00676 send_eivr_event(eivr_events, 'Z', "GENERATOR_FAILURE", chan);
00677 } else {
00678 u->gen_active = 1;
00679 }
00680 }
00681 } else if (input[0] == 'S') {
00682 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00683 ast_chan_log(LOG_WARNING, chan, "Queue 'S'et called on unanswered channel\n");
00684 send_eivr_event(eivr_events, 'Z', NULL, chan);
00685 continue;
00686 }
00687 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00688 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00689 send_eivr_event(eivr_events, 'Z', NULL, chan);
00690 strcpy(&input[2], "exception");
00691 }
00692 if (!u->abort_current_sound && !u->playing_silence)
00693 send_eivr_event(eivr_events, 'T', NULL, chan);
00694 AST_LIST_LOCK(&u->playlist);
00695 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00696 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00697 ast_free(entry);
00698 }
00699 if (!u->playing_silence)
00700 u->abort_current_sound = 1;
00701 entry = make_entry(&input[2]);
00702 if (entry)
00703 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00704 AST_LIST_UNLOCK(&u->playlist);
00705 } else if (input[0] == 'A') {
00706 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00707 ast_chan_log(LOG_WARNING, chan, "Queue 'A'ppend called on unanswered channel\n");
00708 send_eivr_event(eivr_events, 'Z', NULL, chan);
00709 continue;
00710 }
00711 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00712 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00713 send_eivr_event(eivr_events, 'Z', NULL, chan);
00714 strcpy(&input[2], "exception");
00715 }
00716 entry = make_entry(&input[2]);
00717 if (entry) {
00718 AST_LIST_LOCK(&u->playlist);
00719 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00720 AST_LIST_UNLOCK(&u->playlist);
00721 }
00722 } else if (input[0] == 'G') {
00723
00724 char response[2048];
00725
00726 ast_chan_log(LOG_NOTICE, chan, "Getting a Variable out of the channel: %s\n", &input[2]);
00727 ast_eivr_getvariable(chan, &input[2], response, sizeof(response));
00728 send_eivr_event(eivr_events, 'G', response, chan);
00729 } else if (input[0] == 'V') {
00730
00731 ast_chan_log(LOG_NOTICE, chan, "Setting a Variable up: %s\n", &input[2]);
00732 ast_eivr_setvariable(chan, &input[2]);
00733 } else if (input[0] == 'L') {
00734 ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]);
00735 } else if (input[0] == 'X') {
00736 ast_chan_log(LOG_NOTICE, chan, "Exiting ExternalIVR: %s\n", &input[2]);
00737
00738 res = 0;
00739 break;
00740 } else if (input[0] == 'E') {
00741 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
00742 send_eivr_event(eivr_events, 'E', NULL, chan);
00743 res = 0;
00744 break;
00745 } else if (input[0] == 'H') {
00746 ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
00747 send_eivr_event(eivr_events, 'H', NULL, chan);
00748 res = -1;
00749 break;
00750 } else if (input[0] == 'O') {
00751 if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
00752 ast_chan_log(LOG_WARNING, chan, "Option called on unanswered channel\n");
00753 send_eivr_event(eivr_events, 'Z', NULL, chan);
00754 continue;
00755 }
00756 if (!strcasecmp(&input[2], "autoclear"))
00757 u->option_autoclear = 1;
00758 else if (!strcasecmp(&input[2], "noautoclear"))
00759 u->option_autoclear = 0;
00760 else
00761 ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
00762 }
00763 } else if (eivr_errors_fd && ready_fd == eivr_errors_fd) {
00764 char input[1024];
00765
00766 if (exception || feof(eivr_errors)) {
00767 ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00768 res = -1;
00769 break;
00770 }
00771 if (fgets(input, sizeof(input), eivr_errors)) {
00772 command = ast_strip(input);
00773 ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
00774 }
00775 } else if ((ready_fd < 0) && ms) {
00776 if (errno == 0 || errno == EINTR)
00777 continue;
00778
00779 ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
00780 break;
00781 }
00782 }
00783
00784
00785 exit:
00786
00787 if (test_available_fd > -1) {
00788 close(test_available_fd);
00789 }
00790
00791 if (eivr_events)
00792 fclose(eivr_events);
00793
00794 if (eivr_commands)
00795 fclose(eivr_commands);
00796
00797 if (eivr_errors)
00798 fclose(eivr_errors);
00799
00800 return res;
00801
00802 }
00803
00804 static int unload_module(void)
00805 {
00806 return ast_unregister_application(app);
00807 }
00808
00809 static int load_module(void)
00810 {
00811 return ast_register_application(app, app_exec, synopsis, descrip);
00812 }
00813
00814 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");