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