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
00035
00036
00037
00038 #include "asterisk.h"
00039
00040 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 369142 $")
00041
00042 #include <signal.h>
00043
00044 #include "asterisk/lock.h"
00045 #include "asterisk/file.h"
00046 #include "asterisk/channel.h"
00047 #include "asterisk/pbx.h"
00048 #include "asterisk/module.h"
00049 #include "asterisk/linkedlists.h"
00050 #include "asterisk/app.h"
00051 #include "asterisk/utils.h"
00052 #include "asterisk/tcptls.h"
00053 #include "asterisk/astobj2.h"
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097 static const char app[] = "ExternalIVR";
00098
00099
00100 #define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, ast_channel_name(channel) , ## __VA_ARGS__)
00101
00102
00103 #define EIVR_CMD_APND 'A'
00104 #define EIVR_CMD_DTMF 'D'
00105 #define EIVR_CMD_EXIT 'E'
00106 #define EIVR_CMD_GET 'G'
00107 #define EIVR_CMD_HGUP 'H'
00108 #define EIVR_CMD_IRPT 'I'
00109 #define EIVR_CMD_LOG 'L'
00110 #define EIVR_CMD_OPT 'O'
00111 #define EIVR_CMD_PARM 'P'
00112 #define EIVR_CMD_SQUE 'S'
00113 #define EIVR_CMD_ANS 'T'
00114 #define EIVR_CMD_SVAR 'V'
00115 #define EIVR_CMD_XIT 'X'
00116
00117 #define EXTERNALIVR_PORT 2949
00118
00119 enum options_flags {
00120 noanswer = (1 << 0),
00121 ignore_hangup = (1 << 1),
00122 run_dead = (1 << 2),
00123 };
00124
00125 AST_APP_OPTIONS(app_opts, {
00126 AST_APP_OPTION('n', noanswer),
00127 AST_APP_OPTION('i', ignore_hangup),
00128 AST_APP_OPTION('d', run_dead),
00129 });
00130
00131 struct playlist_entry {
00132 AST_LIST_ENTRY(playlist_entry) list;
00133 char filename[1];
00134 };
00135
00136 struct ivr_localuser {
00137 struct ast_channel *chan;
00138 AST_LIST_HEAD(playlist, playlist_entry) playlist;
00139 AST_LIST_HEAD(finishlist, playlist_entry) finishlist;
00140 int abort_current_sound;
00141 int playing_silence;
00142 int option_autoclear;
00143 int gen_active;
00144 };
00145
00146
00147 struct gen_state {
00148 struct ivr_localuser *u;
00149 struct ast_filestream *stream;
00150 struct playlist_entry *current;
00151 int sample_queue;
00152 };
00153
00154 static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
00155 int *eivr_events_fd, int *eivr_commands_fd, int *eivr_errors_fd,
00156 const struct ast_str *args, const struct ast_flags flags);
00157
00158 static void send_eivr_event(FILE *handle, const char event, const char *data,
00159 const struct ast_channel *chan)
00160 {
00161 struct ast_str *tmp = ast_str_create(12);
00162
00163 ast_str_append(&tmp, 0, "%c,%10d", event, (int)time(NULL));
00164 if (data) {
00165 ast_str_append(&tmp, 0, ",%s", data);
00166 }
00167
00168 fprintf(handle, "%s\n", ast_str_buffer(tmp));
00169 ast_debug(1, "sent '%s'\n", ast_str_buffer(tmp));
00170 ast_free(tmp);
00171 }
00172
00173 static void *gen_alloc(struct ast_channel *chan, void *params)
00174 {
00175 struct ivr_localuser *u = params;
00176 struct gen_state *state;
00177
00178 if (!(state = ast_calloc(1, sizeof(*state))))
00179 return NULL;
00180
00181 state->u = u;
00182
00183 return state;
00184 }
00185
00186 static void gen_closestream(struct gen_state *state)
00187 {
00188 if (!state->stream)
00189 return;
00190
00191 ast_closestream(state->stream);
00192 ast_channel_stream_set(state->u->chan, NULL);
00193 state->stream = NULL;
00194 }
00195
00196 static void gen_release(struct ast_channel *chan, void *data)
00197 {
00198 struct gen_state *state = data;
00199
00200 gen_closestream(state);
00201 ast_free(data);
00202 }
00203
00204
00205 static int gen_nextfile(struct gen_state *state)
00206 {
00207 struct ivr_localuser *u = state->u;
00208 char *file_to_stream;
00209
00210 u->abort_current_sound = 0;
00211 u->playing_silence = 0;
00212 gen_closestream(state);
00213
00214 while (!state->stream) {
00215 state->current = AST_LIST_FIRST(&u->playlist);
00216 if (state->current) {
00217 file_to_stream = state->current->filename;
00218 } else {
00219 file_to_stream = "silence/10";
00220 u->playing_silence = 1;
00221 }
00222
00223 if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, ast_channel_language(u->chan), 1))) {
00224 ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
00225 AST_LIST_LOCK(&u->playlist);
00226 AST_LIST_REMOVE_HEAD(&u->playlist, list);
00227 AST_LIST_UNLOCK(&u->playlist);
00228 if (!u->playing_silence) {
00229 continue;
00230 } else {
00231 break;
00232 }
00233 }
00234 }
00235
00236 return (!state->stream);
00237 }
00238
00239 static struct ast_frame *gen_readframe(struct gen_state *state)
00240 {
00241 struct ast_frame *f = NULL;
00242 struct ivr_localuser *u = state->u;
00243
00244 if (u->abort_current_sound ||
00245 (u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
00246 gen_closestream(state);
00247 AST_LIST_LOCK(&u->playlist);
00248 gen_nextfile(state);
00249 AST_LIST_UNLOCK(&u->playlist);
00250 }
00251
00252 if (!(state->stream && (f = ast_readframe(state->stream)))) {
00253 if (state->current) {
00254
00255 AST_LIST_LOCK(&u->playlist);
00256 AST_LIST_REMOVE_HEAD(&u->playlist, list);
00257 AST_LIST_UNLOCK(&u->playlist);
00258
00259 AST_LIST_LOCK(&u->finishlist);
00260 AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
00261 AST_LIST_UNLOCK(&u->finishlist);
00262 state->current = NULL;
00263 }
00264 if (!gen_nextfile(state))
00265 f = ast_readframe(state->stream);
00266 }
00267
00268 return f;
00269 }
00270
00271 static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)
00272 {
00273 struct gen_state *state = data;
00274 struct ast_frame *f = NULL;
00275 int res = 0;
00276
00277 state->sample_queue += samples;
00278
00279 while (state->sample_queue > 0) {
00280 if (!(f = gen_readframe(state)))
00281 return -1;
00282
00283 res = ast_write(chan, f);
00284 ast_frfree(f);
00285 if (res < 0) {
00286 ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
00287 return -1;
00288 }
00289 state->sample_queue -= f->samples;
00290 }
00291
00292 return res;
00293 }
00294
00295 static struct ast_generator gen =
00296 {
00297 .alloc = gen_alloc,
00298 .release = gen_release,
00299 .generate = gen_generate,
00300 };
00301
00302 static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
00303 {
00304
00305
00306
00307 char *inbuf, *variable;
00308 const char *value;
00309 int j;
00310 struct ast_str *newstring = ast_str_alloca(outbuflen);
00311
00312 outbuf[0] = '\0';
00313
00314 for (j = 1, inbuf = data; ; j++) {
00315 variable = strsep(&inbuf, ",");
00316 if (variable == NULL) {
00317 int outstrlen = strlen(outbuf);
00318 if (outstrlen && outbuf[outstrlen - 1] == ',') {
00319 outbuf[outstrlen - 1] = 0;
00320 }
00321 break;
00322 }
00323
00324 ast_channel_lock(chan);
00325 if (!(value = pbx_builtin_getvar_helper(chan, variable))) {
00326 value = "";
00327 }
00328
00329 ast_str_append(&newstring, 0, "%s=%s,", variable, value);
00330 ast_channel_unlock(chan);
00331 ast_copy_string(outbuf, ast_str_buffer(newstring), outbuflen);
00332 }
00333 }
00334
00335 static void ast_eivr_setvariable(struct ast_channel *chan, char *data)
00336 {
00337 char *value;
00338
00339 char *inbuf = ast_strdupa(data), *variable;
00340
00341 for (variable = strsep(&inbuf, ","); variable; variable = strsep(&inbuf, ",")) {
00342 ast_debug(1, "Setting up a variable: %s\n", variable);
00343
00344 value = strchr(variable, '=');
00345 if (!value) {
00346 value = "";
00347 } else {
00348 *value++ = '\0';
00349 }
00350 pbx_builtin_setvar_helper(chan, variable, value);
00351 }
00352 }
00353
00354 static void ast_eivr_senddtmf(struct ast_channel *chan, char *vdata)
00355 {
00356
00357 char *data;
00358 int dinterval = 0, duration = 0;
00359 AST_DECLARE_APP_ARGS(args,
00360 AST_APP_ARG(digits);
00361 AST_APP_ARG(dinterval);
00362 AST_APP_ARG(duration);
00363 );
00364
00365 data = ast_strdupa(vdata);
00366 AST_STANDARD_APP_ARGS(args, data);
00367
00368 if (!ast_strlen_zero(args.dinterval)) {
00369 ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
00370 }
00371 if (!ast_strlen_zero(args.duration)) {
00372 ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
00373 }
00374 ast_verb(4, "Sending DTMF: %s %d %d\n", args.digits, dinterval <= 0 ? 250 : dinterval, duration);
00375 ast_dtmf_stream(chan, NULL, args.digits, dinterval <= 0 ? 250 : dinterval, duration);
00376 }
00377
00378 static struct playlist_entry *make_entry(const char *filename)
00379 {
00380 struct playlist_entry *entry;
00381
00382 if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10)))
00383 return NULL;
00384
00385 strcpy(entry->filename, filename);
00386
00387 return entry;
00388 }
00389
00390 static int app_exec(struct ast_channel *chan, const char *data)
00391 {
00392 struct ast_flags flags = { 0, };
00393 char *opts[0];
00394 struct playlist_entry *entry;
00395 int child_stdin[2] = { -1, -1 };
00396 int child_stdout[2] = { -1, -1 };
00397 int child_stderr[2] = { -1, -1 };
00398 int res = -1;
00399 int pid;
00400
00401 struct ast_tcptls_session_instance *ser = NULL;
00402
00403 struct ivr_localuser foo = {
00404 .playlist = AST_LIST_HEAD_INIT_VALUE,
00405 .finishlist = AST_LIST_HEAD_INIT_VALUE,
00406 .gen_active = 0,
00407 .playing_silence = 1,
00408 };
00409 struct ivr_localuser *u = &foo;
00410
00411 char *buf;
00412 int j;
00413 char *s, **app_args, *e;
00414 struct ast_str *comma_delim_args = ast_str_alloca(100);
00415
00416 AST_DECLARE_APP_ARGS(eivr_args,
00417 AST_APP_ARG(application);
00418 AST_APP_ARG(options);
00419 );
00420 AST_DECLARE_APP_ARGS(application_args,
00421 AST_APP_ARG(cmd)[32];
00422 );
00423
00424 u->abort_current_sound = 0;
00425 u->chan = chan;
00426
00427 if (ast_strlen_zero(data)) {
00428 ast_log(LOG_ERROR, "ExternalIVR requires a command to execute\n");
00429 goto exit;
00430 }
00431
00432 buf = ast_strdupa(data);
00433 AST_STANDARD_APP_ARGS(eivr_args, buf);
00434
00435 ast_verb(4, "ExternalIVR received application and arguments: %s\n", eivr_args.application);
00436 ast_verb(4, "ExternalIVR received options: %s\n", eivr_args.options);
00437
00438
00439 if ((s = strchr(eivr_args.application, '('))) {
00440 s[0] = ',';
00441 if ((e = strrchr(s, ')'))) {
00442 *e = '\0';
00443 } else {
00444 ast_log(LOG_ERROR, "Parse error, missing closing parenthesis\n");
00445 goto exit;
00446 }
00447 }
00448
00449 AST_STANDARD_APP_ARGS(application_args, eivr_args.application);
00450 app_args = application_args.argv;
00451
00452
00453 ast_str_reset(comma_delim_args);
00454 for (j = 0; application_args.cmd[j] != NULL; j++) {
00455 ast_str_append(&comma_delim_args, 0, "%s%s", j == 0 ? "" : ",", application_args.cmd[j]);
00456 }
00457
00458
00459 if (eivr_args.options && (s = strchr(eivr_args.options, ','))) {
00460 *s = '\0';
00461 }
00462
00463
00464 ast_verb(4, "Parsing options from: [%s]\n", eivr_args.options);
00465 ast_app_parse_options(app_opts, &flags, opts, eivr_args.options);
00466 if (ast_test_flag(&flags, noanswer)) {
00467 ast_verb(4, "noanswer is set\n");
00468 }
00469 if (ast_test_flag(&flags, ignore_hangup)) {
00470 ast_verb(4, "ignore_hangup is set\n");
00471 }
00472 if (ast_test_flag(&flags, run_dead)) {
00473 ast_verb(4, "run_dead is set\n");
00474 }
00475
00476 if (!(ast_test_flag(&flags, noanswer))) {
00477 ast_verb(3, "Answering channel and starting generator\n");
00478 if (ast_channel_state(chan) != AST_STATE_UP) {
00479 if (ast_test_flag(&flags, run_dead)) {
00480 ast_chan_log(LOG_ERROR, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
00481 goto exit;
00482 }
00483 ast_answer(chan);
00484 }
00485 if (ast_activate_generator(chan, &gen, u) < 0) {
00486 ast_chan_log(LOG_ERROR, chan, "Failed to activate generator\n");
00487 goto exit;
00488 } else {
00489 u->gen_active = 1;
00490 }
00491 }
00492
00493 if (!strncmp(app_args[0], "ivr://", sizeof("ivr://") - 1)) {
00494 struct ast_tcptls_session_args ivr_desc = {
00495 .accept_fd = -1,
00496 .name = "IVR",
00497 };
00498 struct ast_sockaddr *addrs;
00499 int num_addrs = 0, i = 0;
00500 char *host = app_args[0] + sizeof("ivr://") - 1;
00501
00502
00503 ast_debug(1, "Parsing hostname/port for socket connect from \"%s\"\n", host);
00504
00505 if (!(num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC))) {
00506 ast_chan_log(LOG_ERROR, chan, "Unable to locate host '%s'\n", host);
00507 goto exit;
00508 }
00509
00510 for (i = 0; i < num_addrs; i++) {
00511 if (!ast_sockaddr_port(&addrs[i])) {
00512
00513 ast_sockaddr_set_port(&addrs[i], EXTERNALIVR_PORT);
00514 }
00515 ast_sockaddr_copy(&ivr_desc.remote_address, &addrs[i]);
00516 if (!(ser = ast_tcptls_client_create(&ivr_desc)) || !(ser = ast_tcptls_client_start(ser))) {
00517 continue;
00518 }
00519 break;
00520 }
00521
00522 if (i == num_addrs) {
00523 ast_chan_log(LOG_ERROR, chan, "Could not connect to any host. ExternalIVR failed.\n");
00524 goto exit;
00525 }
00526
00527 res = eivr_comm(chan, u, &ser->fd, &ser->fd, NULL, comma_delim_args, flags);
00528
00529 } else {
00530 if (pipe(child_stdin)) {
00531 ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child input: %s\n", strerror(errno));
00532 goto exit;
00533 }
00534 if (pipe(child_stdout)) {
00535 ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child output: %s\n", strerror(errno));
00536 goto exit;
00537 }
00538 if (pipe(child_stderr)) {
00539 ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
00540 goto exit;
00541 }
00542
00543 pid = ast_safe_fork(0);
00544 if (pid < 0) {
00545 ast_log(LOG_ERROR, "Failed to fork(): %s\n", strerror(errno));
00546 goto exit;
00547 }
00548
00549 if (!pid) {
00550
00551 if (ast_opt_high_priority)
00552 ast_set_priority(0);
00553
00554 dup2(child_stdin[0], STDIN_FILENO);
00555 dup2(child_stdout[1], STDOUT_FILENO);
00556 dup2(child_stderr[1], STDERR_FILENO);
00557 ast_close_fds_above_n(STDERR_FILENO);
00558 execv(app_args[0], app_args);
00559 fprintf(stderr, "Failed to execute '%s': %s\n", app_args[0], strerror(errno));
00560 _exit(1);
00561 } else {
00562
00563 close(child_stdin[0]);
00564 child_stdin[0] = -1;
00565 close(child_stdout[1]);
00566 child_stdout[1] = -1;
00567 close(child_stderr[1]);
00568 child_stderr[1] = -1;
00569 res = eivr_comm(chan, u, &child_stdin[1], &child_stdout[0], &child_stderr[0], comma_delim_args, flags);
00570 }
00571 }
00572
00573 exit:
00574 if (u->gen_active) {
00575 ast_deactivate_generator(chan);
00576 }
00577 if (child_stdin[0] > -1) {
00578 close(child_stdin[0]);
00579 }
00580 if (child_stdin[1] > -1) {
00581 close(child_stdin[1]);
00582 }
00583 if (child_stdout[0] > -1) {
00584 close(child_stdout[0]);
00585 }
00586 if (child_stdout[1] > -1) {
00587 close(child_stdout[1]);
00588 }
00589 if (child_stderr[0] > -1) {
00590 close(child_stderr[0]);
00591 }
00592 if (child_stderr[1] > -1) {
00593 close(child_stderr[1]);
00594 }
00595 if (ser) {
00596 ao2_ref(ser, -1);
00597 }
00598 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00599 ast_free(entry);
00600 }
00601 return res;
00602 }
00603
00604 static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u,
00605 int *eivr_events_fd, int *eivr_commands_fd, int *eivr_errors_fd,
00606 const struct ast_str *args, const struct ast_flags flags)
00607 {
00608 struct playlist_entry *entry;
00609 struct ast_frame *f;
00610 int ms;
00611 int exception;
00612 int ready_fd;
00613 int waitfds[2] = { *eivr_commands_fd, (eivr_errors_fd) ? *eivr_errors_fd : -1 };
00614 struct ast_channel *rchan;
00615 int res = -1;
00616 int test_available_fd = -1;
00617 int hangup_info_sent = 0;
00618
00619 FILE *eivr_commands = NULL;
00620 FILE *eivr_errors = NULL;
00621 FILE *eivr_events = NULL;
00622
00623 if (!(eivr_events = fdopen(*eivr_events_fd, "w"))) {
00624 ast_chan_log(LOG_ERROR, chan, "Could not open stream to send events\n");
00625 goto exit;
00626 }
00627 if (!(eivr_commands = fdopen(*eivr_commands_fd, "r"))) {
00628 ast_chan_log(LOG_ERROR, chan, "Could not open stream to receive commands\n");
00629 goto exit;
00630 }
00631 if (eivr_errors_fd) {
00632 if (!(eivr_errors = fdopen(*eivr_errors_fd, "r"))) {
00633 ast_chan_log(LOG_ERROR, chan, "Could not open stream to receive errors\n");
00634 goto exit;
00635 }
00636 }
00637
00638 test_available_fd = open("/dev/null", O_RDONLY);
00639
00640 setvbuf(eivr_events, NULL, _IONBF, 0);
00641 setvbuf(eivr_commands, NULL, _IONBF, 0);
00642 if (eivr_errors) {
00643 setvbuf(eivr_errors, NULL, _IONBF, 0);
00644 }
00645
00646 while (1) {
00647 if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_ZOMBIE)) {
00648 ast_chan_log(LOG_ERROR, chan, "Is a zombie\n");
00649 break;
00650 }
00651 if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) {
00652 if (ast_test_flag(&flags, ignore_hangup)) {
00653 ast_verb(3, "Got check_hangup, but ignore_hangup set so sending 'I' command\n");
00654 send_eivr_event(eivr_events, 'I', "HANGUP", chan);
00655 hangup_info_sent = 1;
00656 } else {
00657 ast_verb(3, "Got check_hangup\n");
00658 send_eivr_event(eivr_events, 'H', NULL, chan);
00659 break;
00660 }
00661 }
00662
00663 ready_fd = 0;
00664 ms = 100;
00665 errno = 0;
00666 exception = 0;
00667
00668 rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd) ? 2 : 1, &exception, &ready_fd, &ms);
00669
00670 if (ast_channel_state(chan) == AST_STATE_UP && !AST_LIST_EMPTY(&u->finishlist)) {
00671 AST_LIST_LOCK(&u->finishlist);
00672 while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
00673 send_eivr_event(eivr_events, 'F', entry->filename, chan);
00674 ast_free(entry);
00675 }
00676 AST_LIST_UNLOCK(&u->finishlist);
00677 }
00678
00679 if (ast_channel_state(chan) == AST_STATE_UP && !(ast_check_hangup(chan)) && rchan) {
00680
00681 f = ast_read(chan);
00682 if (!f) {
00683 ast_verb(3, "Returned no frame\n");
00684 send_eivr_event(eivr_events, 'H', NULL, chan);
00685 break;
00686 }
00687 if (f->frametype == AST_FRAME_DTMF) {
00688 send_eivr_event(eivr_events, f->subclass.integer, NULL, chan);
00689 if (u->option_autoclear) {
00690 AST_LIST_LOCK(&u->playlist);
00691 if (!u->abort_current_sound && !u->playing_silence) {
00692
00693 if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00694 send_eivr_event(eivr_events, 'T', entry->filename, chan);
00695 ast_free(entry);
00696 }
00697 }
00698 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00699 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00700 ast_free(entry);
00701 }
00702 if (!u->playing_silence)
00703 u->abort_current_sound = 1;
00704 AST_LIST_UNLOCK(&u->playlist);
00705 }
00706 } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) {
00707 ast_verb(3, "Got AST_CONTROL_HANGUP\n");
00708 send_eivr_event(eivr_events, 'H', NULL, chan);
00709 if (f->data.uint32) {
00710 ast_channel_hangupcause_set(chan, f->data.uint32);
00711 }
00712 ast_frfree(f);
00713 break;
00714 }
00715 ast_frfree(f);
00716 } else if (ready_fd == *eivr_commands_fd) {
00717 char input[1024];
00718
00719 if (exception || (dup2(*eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) {
00720 ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
00721 break;
00722 }
00723
00724 if (!fgets(input, sizeof(input), eivr_commands)) {
00725 continue;
00726 }
00727
00728 ast_strip(input);
00729 ast_verb(4, "got command '%s'\n", input);
00730
00731 if (strlen(input) < 3) {
00732 continue;
00733 }
00734
00735 if (input[0] == EIVR_CMD_PARM) {
00736 struct ast_str *tmp = (struct ast_str *) args;
00737 send_eivr_event(eivr_events, 'P', ast_str_buffer(tmp), chan);
00738 } else if (input[0] == EIVR_CMD_DTMF) {
00739 ast_verb(4, "Sending DTMF: %s\n", &input[2]);
00740 ast_eivr_senddtmf(chan, &input[2]);
00741 } else if (input[0] == EIVR_CMD_ANS) {
00742 ast_verb(3, "Answering channel if needed and starting generator\n");
00743 if (ast_channel_state(chan) != AST_STATE_UP) {
00744 if (ast_test_flag(&flags, run_dead)) {
00745 ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
00746 send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
00747 continue;
00748 }
00749 if (ast_answer(chan)) {
00750 ast_chan_log(LOG_WARNING, chan, "Failed to answer channel\n");
00751 send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
00752 continue;
00753 }
00754 }
00755 if (!(u->gen_active)) {
00756 if (ast_activate_generator(chan, &gen, u) < 0) {
00757 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
00758 send_eivr_event(eivr_events, 'Z', "GENERATOR_FAILURE", chan);
00759 } else {
00760 u->gen_active = 1;
00761 }
00762 }
00763 } else if (input[0] == EIVR_CMD_IRPT) {
00764 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
00765 ast_chan_log(LOG_WARNING, chan, "Queue 'I'nterrupt called on unanswered channel\n");
00766 send_eivr_event(eivr_events, 'Z', NULL, chan);
00767 continue;
00768 }
00769 AST_LIST_LOCK(&u->playlist);
00770 if (!u->abort_current_sound && !u->playing_silence) {
00771
00772 if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00773 send_eivr_event(eivr_events, 'T', entry->filename, chan);
00774 ast_free(entry);
00775 }
00776 }
00777 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00778 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00779 ast_free(entry);
00780 }
00781 if (!u->playing_silence) {
00782 u->abort_current_sound = 1;
00783 }
00784 AST_LIST_UNLOCK(&u->playlist);
00785 } else if (input[0] == EIVR_CMD_SQUE) {
00786 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
00787 ast_chan_log(LOG_WARNING, chan, "Queue re'S'et called on unanswered channel\n");
00788 send_eivr_event(eivr_events, 'Z', NULL, chan);
00789 continue;
00790 }
00791 if (!ast_fileexists(&input[2], NULL, ast_channel_language(u->chan))) {
00792 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00793 send_eivr_event(eivr_events, 'Z', &input[2], chan);
00794 } else {
00795 AST_LIST_LOCK(&u->playlist);
00796 if (!u->abort_current_sound && !u->playing_silence) {
00797
00798 if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00799 send_eivr_event(eivr_events, 'T', entry->filename, chan);
00800 ast_free(entry);
00801 }
00802 }
00803 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00804 send_eivr_event(eivr_events, 'D', entry->filename, chan);
00805 ast_free(entry);
00806 }
00807 if (!u->playing_silence) {
00808 u->abort_current_sound = 1;
00809 }
00810 entry = make_entry(&input[2]);
00811 if (entry) {
00812 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00813 }
00814 AST_LIST_UNLOCK(&u->playlist);
00815 }
00816 } else if (input[0] == EIVR_CMD_APND) {
00817 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
00818 ast_chan_log(LOG_WARNING, chan, "Queue 'A'ppend called on unanswered channel\n");
00819 send_eivr_event(eivr_events, 'Z', NULL, chan);
00820 continue;
00821 }
00822 if (!ast_fileexists(&input[2], NULL, ast_channel_language(u->chan))) {
00823 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00824 send_eivr_event(eivr_events, 'Z', &input[2], chan);
00825 } else {
00826 entry = make_entry(&input[2]);
00827 if (entry) {
00828 AST_LIST_LOCK(&u->playlist);
00829 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00830 AST_LIST_UNLOCK(&u->playlist);
00831 }
00832 }
00833 } else if (input[0] == EIVR_CMD_GET) {
00834 char response[2048];
00835 ast_verb(4, "Retriving Variables from channel: %s\n", &input[2]);
00836 ast_eivr_getvariable(chan, &input[2], response, sizeof(response));
00837 send_eivr_event(eivr_events, 'G', response, chan);
00838 } else if (input[0] == EIVR_CMD_SVAR) {
00839 ast_verb(4, "Setting Variables in channel: %s\n", &input[2]);
00840 ast_eivr_setvariable(chan, &input[2]);
00841 } else if (input[0] == EIVR_CMD_LOG) {
00842 ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]);
00843 } else if (input[0] == EIVR_CMD_XIT) {
00844 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
00845 ast_chan_log(LOG_WARNING, chan, "e'X'it command is depricated, use 'E'xit instead\n");
00846 res = 0;
00847 break;
00848 } else if (input[0] == EIVR_CMD_EXIT) {
00849 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
00850 send_eivr_event(eivr_events, 'E', NULL, chan);
00851 res = 0;
00852 break;
00853 } else if (input[0] == EIVR_CMD_HGUP) {
00854 ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
00855 send_eivr_event(eivr_events, 'H', NULL, chan);
00856 break;
00857 } else if (input[0] == EIVR_CMD_OPT) {
00858 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
00859 ast_chan_log(LOG_WARNING, chan, "Option called on unanswered channel\n");
00860 send_eivr_event(eivr_events, 'Z', NULL, chan);
00861 continue;
00862 }
00863 if (!strcasecmp(&input[2], "autoclear"))
00864 u->option_autoclear = 1;
00865 else if (!strcasecmp(&input[2], "noautoclear"))
00866 u->option_autoclear = 0;
00867 else
00868 ast_chan_log(LOG_WARNING, chan, "Unknown option requested: %s\n", &input[2]);
00869 }
00870 } else if (eivr_errors_fd && (ready_fd == *eivr_errors_fd)) {
00871 char input[1024];
00872
00873 if (exception || feof(eivr_errors)) {
00874 ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
00875 break;
00876 }
00877 if (fgets(input, sizeof(input), eivr_errors)) {
00878 ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", ast_strip(input));
00879 }
00880 } else if ((ready_fd < 0) && ms) {
00881 if (errno == 0 || errno == EINTR)
00882 continue;
00883
00884 ast_chan_log(LOG_ERROR, chan, "Wait failed (%s)\n", strerror(errno));
00885 break;
00886 }
00887 }
00888
00889 exit:
00890 if (test_available_fd > -1) {
00891 close(test_available_fd);
00892 }
00893 if (eivr_events) {
00894 fclose(eivr_events);
00895 *eivr_events_fd = -1;
00896 }
00897 if (eivr_commands) {
00898 fclose(eivr_commands);
00899 *eivr_commands_fd = -1;
00900 }
00901 if (eivr_errors) {
00902 fclose(eivr_errors);
00903 *eivr_errors_fd = -1;
00904 }
00905 return res;
00906 }
00907
00908 static int unload_module(void)
00909 {
00910 return ast_unregister_application(app);
00911 }
00912
00913 static int load_module(void)
00914 {
00915 return ast_register_application_xml(app, app_exec);
00916 }
00917
00918 AST_MODULE_INFO_STANDARD(ASTERISK_GPL_KEY, "External IVR Interface Application");