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