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