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