#include "asterisk.h"
#include <signal.h>
#include <sys/capability.h>
#include "asterisk/lock.h"
#include "asterisk/file.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/module.h"
#include "asterisk/linkedlists.h"
#include "asterisk/app.h"
#include "asterisk/utils.h"
Go to the source code of this file.
Data Structures | |
struct | gen_state |
struct | ivr_localuser |
struct | ivr_localuser::finishlist |
struct | ivr_localuser::playlist |
struct | playlist_entry |
Defines | |
#define | ast_chan_log(level, channel, format,) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__) |
Functions | |
static void | __reg_module (void) |
static void | __unreg_module (void) |
static int | app_exec (struct ast_channel *chan, void *data) |
static void | ast_eivr_getvariable (struct ast_channel *chan, char *data, char *outbuf, int outbuflen) |
static void | ast_eivr_setvariable (struct ast_channel *chan, char *data) |
static int | eivr_comm (struct ast_channel *chan, struct ivr_localuser *u, int eivr_events_fd, int eivr_commands_fd, int eivr_errors_fd, const char *args) |
static void * | gen_alloc (struct ast_channel *chan, void *params) |
static void | gen_closestream (struct gen_state *state) |
static int | gen_generate (struct ast_channel *chan, void *data, int len, int samples) |
static int | gen_nextfile (struct gen_state *state) |
static struct ast_frame * | gen_readframe (struct gen_state *state) |
static void | gen_release (struct ast_channel *chan, void *data) |
static int | load_module (void) |
static struct playlist_entry * | make_entry (const char *filename) |
static void | send_eivr_event (FILE *handle, const char event, const char *data, const struct ast_channel *chan) |
static int | unload_module (void) |
Variables | |
static struct ast_module_info | __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "External IVR Interface Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } |
static const char * | app = "ExternalIVR" |
static const struct ast_module_info * | ast_module_info = &__mod_info |
static const char * | descrip |
static struct ast_generator | gen |
static const char * | synopsis = "Interfaces with an external IVR application" |
Definition in file app_externalivr.c.
#define ast_chan_log | ( | level, | |||
channel, | |||||
format | ) | ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__) |
Definition at line 71 of file app_externalivr.c.
Referenced by app_exec(), eivr_comm(), gen_generate(), gen_nextfile(), and send_eivr_event().
static void __reg_module | ( | void | ) | [static] |
Definition at line 672 of file app_externalivr.c.
static void __unreg_module | ( | void | ) | [static] |
Definition at line 672 of file app_externalivr.c.
static int app_exec | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 297 of file app_externalivr.c.
References ast_channel::_state, ivr_localuser::abort_current_sound, ast_activate_generator(), ast_answer(), AST_APP_ARG, ast_chan_log, ast_deactivate_generator(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD_INIT_VALUE, AST_LIST_REMOVE_HEAD, ast_log(), ast_opt_high_priority, ast_set_priority(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), buf, chan, ivr_localuser::chan, eivr_comm(), errno, gen, playlist_entry::list, LOG_WARNING, and ivr_localuser::playlist.
00298 { 00299 struct playlist_entry *entry; 00300 int child_stdin[2] = { 0,0 }; 00301 int child_stdout[2] = { 0,0 }; 00302 int child_stderr[2] = { 0,0 }; 00303 int res = -1; 00304 int gen_active = 0; 00305 int pid; 00306 char *buf, *comma_delim_argbuf; 00307 struct ivr_localuser foo = { 00308 .playlist = AST_LIST_HEAD_INIT_VALUE, 00309 .finishlist = AST_LIST_HEAD_INIT_VALUE, 00310 }; 00311 struct ivr_localuser *u = &foo; 00312 sigset_t fullset, oldset; 00313 AST_DECLARE_APP_ARGS(args, 00314 AST_APP_ARG(cmd)[32]; 00315 ); 00316 00317 sigfillset(&fullset); 00318 pthread_sigmask(SIG_BLOCK, &fullset, &oldset); 00319 00320 u->abort_current_sound = 0; 00321 u->chan = chan; 00322 00323 if (ast_strlen_zero(data)) { 00324 ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n"); 00325 return -1; 00326 } 00327 00328 buf = ast_strdupa(data); 00329 AST_STANDARD_APP_ARGS(args, buf); 00330 00331 /* copy args and replace commas with pipes */ 00332 comma_delim_argbuf = ast_strdupa(data); 00333 00334 if (pipe(child_stdin)) { 00335 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno)); 00336 goto exit; 00337 } 00338 if (pipe(child_stdout)) { 00339 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno)); 00340 goto exit; 00341 } 00342 if (pipe(child_stderr)) { 00343 ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno)); 00344 goto exit; 00345 } 00346 if (chan->_state != AST_STATE_UP) { 00347 ast_answer(chan); 00348 } 00349 if (ast_activate_generator(chan, &gen, u) < 0) { 00350 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n"); 00351 goto exit; 00352 } else 00353 gen_active = 1; 00354 00355 pid = fork(); 00356 if (pid < 0) { 00357 ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno)); 00358 goto exit; 00359 } 00360 00361 if (!pid) { 00362 /* child process */ 00363 int i; 00364 #ifdef HAVE_CAP 00365 cap_t cap = cap_from_text("cap_net_admin-eip"); 00366 00367 if (cap_set_proc(cap)) { 00368 /* Careful with order! Logging cannot happen after we close FDs */ 00369 ast_log(LOG_WARNING, "Unable to remove capabilities.\n"); 00370 } 00371 cap_free(cap); 00372 #endif 00373 00374 signal(SIGPIPE, SIG_DFL); 00375 pthread_sigmask(SIG_UNBLOCK, &fullset, NULL); 00376 00377 if (ast_opt_high_priority) 00378 ast_set_priority(0); 00379 00380 dup2(child_stdin[0], STDIN_FILENO); 00381 dup2(child_stdout[1], STDOUT_FILENO); 00382 dup2(child_stderr[1], STDERR_FILENO); 00383 for (i = STDERR_FILENO + 1; i < 1024; i++) 00384 close(i); 00385 execv(args.cmd[0], args.cmd); 00386 fprintf(stderr, "Failed to execute '%s': %s\n", args.cmd[0], strerror(errno)); 00387 _exit(1); 00388 } else { 00389 /* parent process */ 00390 00391 close(child_stdin[0]); 00392 child_stdin[0] = 0; 00393 close(child_stdout[1]); 00394 child_stdout[1] = 0; 00395 close(child_stderr[1]); 00396 child_stderr[1] = 0; 00397 res = eivr_comm(chan, u, child_stdin[1], child_stdout[0], child_stderr[0], comma_delim_argbuf); 00398 00399 exit: 00400 if (gen_active) 00401 ast_deactivate_generator(chan); 00402 00403 if (child_stdin[0]) 00404 close(child_stdin[0]); 00405 00406 if (child_stdin[1]) 00407 close(child_stdin[1]); 00408 00409 if (child_stdout[0]) 00410 close(child_stdout[0]); 00411 00412 if (child_stdout[1]) 00413 close(child_stdout[1]); 00414 00415 if (child_stderr[0]) 00416 close(child_stderr[0]); 00417 00418 if (child_stderr[1]) 00419 close(child_stderr[1]); 00420 00421 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) 00422 ast_free(entry); 00423 00424 return res; 00425 } 00426 }
static void ast_eivr_getvariable | ( | struct ast_channel * | chan, | |
char * | data, | |||
char * | outbuf, | |||
int | outbuflen | |||
) | [static] |
Definition at line 236 of file app_externalivr.c.
References ast_copy_string(), ast_str_alloca, ast_str_append(), chan, inbuf(), pbx_builtin_getvar_helper(), ast_str::str, and strsep().
Referenced by eivr_comm().
00237 { 00238 /* original input data: "G,var1,var2," */ 00239 /* data passed as "data": "var1,var2" */ 00240 00241 char *inbuf, *variable; 00242 const char *value; 00243 int j; 00244 struct ast_str *newstring = ast_str_alloca(outbuflen); 00245 00246 outbuf[0] = '\0'; 00247 00248 for (j = 1, inbuf = data; ; j++) { 00249 variable = strsep(&inbuf, ","); 00250 if (variable == NULL) { 00251 int outstrlen = strlen(outbuf); 00252 if(outstrlen && outbuf[outstrlen - 1] == ',') { 00253 outbuf[outstrlen - 1] = 0; 00254 } 00255 break; 00256 } 00257 00258 value = pbx_builtin_getvar_helper(chan, variable); 00259 if(!value) 00260 value = ""; 00261 ast_str_append(&newstring, 0, "%s=%s,", variable, value); 00262 ast_copy_string(outbuf, newstring->str, outbuflen); 00263 } 00264 };
static void ast_eivr_setvariable | ( | struct ast_channel * | chan, | |
char * | data | |||
) | [static] |
Definition at line 266 of file app_externalivr.c.
References ast_debug, ast_strdupa, chan, inbuf(), pbx_builtin_setvar_helper(), and strsep().
Referenced by eivr_comm().
00267 { 00268 char *value; 00269 00270 char *inbuf = ast_strdupa(data), *variable; 00271 00272 for (variable = strsep(&inbuf, ","); variable; variable = strsep(&inbuf, ",")) { 00273 ast_debug(1, "Setting up a variable: %s\n", variable); 00274 /* variable contains "varname=value" */ 00275 value = strchr(variable, '='); 00276 if (!value) { 00277 value = ""; 00278 } else { 00279 *value++ = '\0'; 00280 } 00281 pbx_builtin_setvar_helper(chan, variable, value); 00282 } 00283 };
static int eivr_comm | ( | struct ast_channel * | chan, | |
struct ivr_localuser * | u, | |||
int | eivr_events_fd, | |||
int | eivr_commands_fd, | |||
int | eivr_errors_fd, | |||
const char * | args | |||
) | [static] |
Definition at line 428 of file app_externalivr.c.
References ivr_localuser::abort_current_sound, ast_chan_log, ast_check_hangup(), AST_CONTROL_HANGUP, ast_eivr_getvariable(), ast_eivr_setvariable(), ast_fileexists(), AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_free, ast_frfree, AST_LIST_EMPTY, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_read(), ast_strip(), ast_test_flag, ast_waitfor_nandfds(), ivr_localuser::chan, chan, errno, f, playlist_entry::filename, ivr_localuser::finishlist, input(), ast_channel::language, playlist_entry::list, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, make_entry(), ivr_localuser::option_autoclear, option_debug, ivr_localuser::playing_silence, ivr_localuser::playlist, and send_eivr_event().
Referenced by app_exec().
00431 { 00432 struct playlist_entry *entry; 00433 struct ast_frame *f; 00434 int ms; 00435 int exception; 00436 int ready_fd; 00437 int waitfds[2] = { eivr_commands_fd, eivr_errors_fd }; 00438 struct ast_channel *rchan; 00439 char *command; 00440 int res = -1; 00441 int test_available_fd = -1; 00442 00443 FILE *eivr_commands = NULL; 00444 FILE *eivr_errors = NULL; 00445 FILE *eivr_events = NULL; 00446 00447 if (!(eivr_events = fdopen(eivr_events_fd, "w"))) { 00448 ast_chan_log(LOG_WARNING, chan, "Could not open stream to send events\n"); 00449 goto exit; 00450 } 00451 if (!(eivr_commands = fdopen(eivr_commands_fd, "r"))) { 00452 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive commands\n"); 00453 goto exit; 00454 } 00455 if(eivr_errors_fd) { /*if opening a socket connection, error stream will not be used*/ 00456 if (!(eivr_errors = fdopen(eivr_errors_fd, "r"))) { 00457 ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive errors\n"); 00458 goto exit; 00459 } 00460 } 00461 00462 test_available_fd = open("/dev/null", O_RDONLY); 00463 00464 setvbuf(eivr_events, NULL, _IONBF, 0); 00465 setvbuf(eivr_commands, NULL, _IONBF, 0); 00466 if(eivr_errors) 00467 setvbuf(eivr_errors, NULL, _IONBF, 0); 00468 00469 res = 0; 00470 00471 while (1) { 00472 if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) { 00473 ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n"); 00474 res = -1; 00475 break; 00476 } 00477 if (ast_check_hangup(chan)) { 00478 ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n"); 00479 send_eivr_event(eivr_events, 'H', NULL, chan); 00480 res = -1; 00481 break; 00482 } 00483 00484 ready_fd = 0; 00485 ms = 100; 00486 errno = 0; 00487 exception = 0; 00488 00489 rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd == 0) ? 1 : 2, &exception, &ready_fd, &ms); 00490 00491 if (!AST_LIST_EMPTY(&u->finishlist)) { 00492 AST_LIST_LOCK(&u->finishlist); 00493 while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) { 00494 send_eivr_event(eivr_events, 'F', entry->filename, chan); 00495 ast_free(entry); 00496 } 00497 AST_LIST_UNLOCK(&u->finishlist); 00498 } 00499 00500 if (rchan) { 00501 /* the channel has something */ 00502 f = ast_read(chan); 00503 if (!f) { 00504 ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n"); 00505 send_eivr_event(eivr_events, 'H', NULL, chan); 00506 res = -1; 00507 break; 00508 } 00509 if (f->frametype == AST_FRAME_DTMF) { 00510 send_eivr_event(eivr_events, f->subclass, NULL, chan); 00511 if (u->option_autoclear) { 00512 if (!u->abort_current_sound && !u->playing_silence) 00513 send_eivr_event(eivr_events, 'T', NULL, chan); 00514 AST_LIST_LOCK(&u->playlist); 00515 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { 00516 send_eivr_event(eivr_events, 'D', entry->filename, chan); 00517 ast_free(entry); 00518 } 00519 if (!u->playing_silence) 00520 u->abort_current_sound = 1; 00521 AST_LIST_UNLOCK(&u->playlist); 00522 } 00523 } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) { 00524 ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n"); 00525 send_eivr_event(eivr_events, 'H', NULL, chan); 00526 ast_frfree(f); 00527 res = -1; 00528 break; 00529 } 00530 ast_frfree(f); 00531 } else if (ready_fd == eivr_commands_fd) { 00532 char input[1024]; 00533 00534 if (exception || (dup2(eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) { 00535 ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); 00536 res = -1; 00537 break; 00538 } 00539 00540 if (!fgets(input, sizeof(input), eivr_commands)) 00541 continue; 00542 00543 command = ast_strip(input); 00544 00545 if (option_debug) 00546 ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input); 00547 00548 if (strlen(input) < 4) 00549 continue; 00550 00551 if (input[0] == 'P') { 00552 send_eivr_event(eivr_events, 'P', args, chan); 00553 00554 } else if (input[0] == 'S') { 00555 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { 00556 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); 00557 send_eivr_event(eivr_events, 'Z', NULL, chan); 00558 strcpy(&input[2], "exception"); 00559 } 00560 if (!u->abort_current_sound && !u->playing_silence) 00561 send_eivr_event(eivr_events, 'T', NULL, chan); 00562 AST_LIST_LOCK(&u->playlist); 00563 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) { 00564 send_eivr_event(eivr_events, 'D', entry->filename, chan); 00565 ast_free(entry); 00566 } 00567 if (!u->playing_silence) 00568 u->abort_current_sound = 1; 00569 entry = make_entry(&input[2]); 00570 if (entry) 00571 AST_LIST_INSERT_TAIL(&u->playlist, entry, list); 00572 AST_LIST_UNLOCK(&u->playlist); 00573 } else if (input[0] == 'A') { 00574 if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) { 00575 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]); 00576 send_eivr_event(eivr_events, 'Z', NULL, chan); 00577 strcpy(&input[2], "exception"); 00578 } 00579 entry = make_entry(&input[2]); 00580 if (entry) { 00581 AST_LIST_LOCK(&u->playlist); 00582 AST_LIST_INSERT_TAIL(&u->playlist, entry, list); 00583 AST_LIST_UNLOCK(&u->playlist); 00584 } 00585 } else if (input[0] == 'G') { 00586 /* A get variable message: "G,variable1,variable2,..." */ 00587 char response[2048]; 00588 00589 ast_chan_log(LOG_NOTICE, chan, "Getting a Variable out of the channel: %s\n", &input[2]); 00590 ast_eivr_getvariable(chan, &input[2], response, sizeof(response)); 00591 send_eivr_event(eivr_events, 'G', response, chan); 00592 } else if (input[0] == 'V') { 00593 /* A set variable message: "V,variablename=foo" */ 00594 ast_chan_log(LOG_NOTICE, chan, "Setting a Variable up: %s\n", &input[2]); 00595 ast_eivr_setvariable(chan, &input[2]); 00596 } else if (input[0] == 'L') { 00597 ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]); 00598 } else if (input[0] == 'X') { 00599 ast_chan_log(LOG_NOTICE, chan, "Exiting ExternalIVR: %s\n", &input[2]); 00600 /*! \todo add deprecation debug message for X command here */ 00601 res = 0; 00602 break; 00603 } else if (input[0] == 'E') { 00604 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]); 00605 send_eivr_event(eivr_events, 'E', NULL, chan); 00606 res = 0; 00607 break; 00608 } else if (input[0] == 'H') { 00609 ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]); 00610 send_eivr_event(eivr_events, 'H', NULL, chan); 00611 res = -1; 00612 break; 00613 } else if (input[0] == 'O') { 00614 if (!strcasecmp(&input[2], "autoclear")) 00615 u->option_autoclear = 1; 00616 else if (!strcasecmp(&input[2], "noautoclear")) 00617 u->option_autoclear = 0; 00618 else 00619 ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]); 00620 } 00621 } else if (eivr_errors_fd && ready_fd == eivr_errors_fd) { 00622 char input[1024]; 00623 00624 if (exception || feof(eivr_errors)) { 00625 ast_chan_log(LOG_WARNING, chan, "Child process went away\n"); 00626 res = -1; 00627 break; 00628 } 00629 if (fgets(input, sizeof(input), eivr_errors)) { 00630 command = ast_strip(input); 00631 ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command); 00632 } 00633 } else if ((ready_fd < 0) && ms) { 00634 if (errno == 0 || errno == EINTR) 00635 continue; 00636 00637 ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno)); 00638 break; 00639 } 00640 } 00641 00642 00643 exit: 00644 00645 if (test_available_fd > -1) { 00646 close(test_available_fd); 00647 } 00648 00649 if (eivr_events) 00650 fclose(eivr_events); 00651 00652 if (eivr_commands) 00653 fclose(eivr_commands); 00654 00655 if (eivr_errors) 00656 fclose(eivr_errors); 00657 00658 return res; 00659 00660 }
static void* gen_alloc | ( | struct ast_channel * | chan, | |
void * | params | |||
) | [static] |
Definition at line 115 of file app_externalivr.c.
References ast_calloc, and gen_state::u.
00116 { 00117 struct ivr_localuser *u = params; 00118 struct gen_state *state; 00119 00120 if (!(state = ast_calloc(1, sizeof(*state)))) 00121 return NULL; 00122 00123 state->u = u; 00124 00125 return state; 00126 }
static void gen_closestream | ( | struct gen_state * | state | ) | [static] |
Definition at line 128 of file app_externalivr.c.
References ast_closestream(), ivr_localuser::chan, ast_channel::stream, gen_state::stream, and gen_state::u.
Referenced by gen_nextfile(), gen_readframe(), and gen_release().
00129 { 00130 if (!state->stream) 00131 return; 00132 00133 ast_closestream(state->stream); 00134 state->u->chan->stream = NULL; 00135 state->stream = NULL; 00136 }
static int gen_generate | ( | struct ast_channel * | chan, | |
void * | data, | |||
int | len, | |||
int | samples | |||
) | [static] |
Definition at line 205 of file app_externalivr.c.
References ast_chan_log, ast_frfree, ast_write(), chan, errno, f, gen_readframe(), LOG_WARNING, and gen_state::sample_queue.
00206 { 00207 struct gen_state *state = data; 00208 struct ast_frame *f = NULL; 00209 int res = 0; 00210 00211 state->sample_queue += samples; 00212 00213 while (state->sample_queue > 0) { 00214 if (!(f = gen_readframe(state))) 00215 return -1; 00216 00217 res = ast_write(chan, f); 00218 ast_frfree(f); 00219 if (res < 0) { 00220 ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno)); 00221 return -1; 00222 } 00223 state->sample_queue -= f->samples; 00224 } 00225 00226 return res; 00227 }
static int gen_nextfile | ( | struct gen_state * | state | ) | [static] |
Definition at line 147 of file app_externalivr.c.
References ivr_localuser::abort_current_sound, ast_chan_log, AST_LIST_REMOVE_HEAD, ast_openstream_full(), ivr_localuser::chan, gen_state::current, errno, playlist_entry::filename, gen_closestream(), ast_channel::language, playlist_entry::list, LOG_WARNING, ivr_localuser::playing_silence, ivr_localuser::playlist, gen_state::stream, and gen_state::u.
Referenced by gen_readframe().
00148 { 00149 struct ivr_localuser *u = state->u; 00150 char *file_to_stream; 00151 00152 u->abort_current_sound = 0; 00153 u->playing_silence = 0; 00154 gen_closestream(state); 00155 00156 while (!state->stream) { 00157 state->current = AST_LIST_REMOVE_HEAD(&u->playlist, list); 00158 if (state->current) { 00159 file_to_stream = state->current->filename; 00160 } else { 00161 file_to_stream = "silence/10"; 00162 u->playing_silence = 1; 00163 } 00164 00165 if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) { 00166 ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno)); 00167 if (!u->playing_silence) { 00168 continue; 00169 } else { 00170 break; 00171 } 00172 } 00173 } 00174 00175 return (!state->stream); 00176 }
Definition at line 178 of file app_externalivr.c.
References ivr_localuser::abort_current_sound, AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_readframe(), gen_state::current, f, ivr_localuser::finishlist, gen_closestream(), gen_nextfile(), playlist_entry::list, ivr_localuser::playing_silence, ivr_localuser::playlist, gen_state::stream, and gen_state::u.
Referenced by gen_generate().
00179 { 00180 struct ast_frame *f = NULL; 00181 struct ivr_localuser *u = state->u; 00182 00183 if (u->abort_current_sound || 00184 (u->playing_silence && AST_LIST_FIRST(&u->playlist))) { 00185 gen_closestream(state); 00186 AST_LIST_LOCK(&u->playlist); 00187 gen_nextfile(state); 00188 AST_LIST_UNLOCK(&u->playlist); 00189 } 00190 00191 if (!(state->stream && (f = ast_readframe(state->stream)))) { 00192 if (state->current) { 00193 AST_LIST_LOCK(&u->finishlist); 00194 AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list); 00195 AST_LIST_UNLOCK(&u->finishlist); 00196 state->current = NULL; 00197 } 00198 if (!gen_nextfile(state)) 00199 f = ast_readframe(state->stream); 00200 } 00201 00202 return f; 00203 }
static void gen_release | ( | struct ast_channel * | chan, | |
void * | data | |||
) | [static] |
Definition at line 138 of file app_externalivr.c.
References ast_free, and gen_closestream().
00139 { 00140 struct gen_state *state = data; 00141 00142 gen_closestream(state); 00143 ast_free(data); 00144 }
static int load_module | ( | void | ) | [static] |
Definition at line 667 of file app_externalivr.c.
References app_exec, and ast_register_application.
00668 { 00669 return ast_register_application(app, app_exec, synopsis, descrip); 00670 }
static struct playlist_entry* make_entry | ( | const char * | filename | ) | [static] |
Definition at line 285 of file app_externalivr.c.
References ast_calloc.
Referenced by eivr_comm().
00286 { 00287 struct playlist_entry *entry; 00288 00289 if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10))) /* XXX why 10 ? */ 00290 return NULL; 00291 00292 strcpy(entry->filename, filename); 00293 00294 return entry; 00295 }
static void send_eivr_event | ( | FILE * | handle, | |
const char | event, | |||
const char * | data, | |||
const struct ast_channel * | chan | |||
) | [static] |
Definition at line 99 of file app_externalivr.c.
References ast_chan_log, chan, LOG_DEBUG, and option_debug.
Referenced by eivr_comm().
00101 { 00102 char tmp[256]; 00103 00104 if (!data) { 00105 snprintf(tmp, sizeof(tmp), "%c,%10d", event, (int)time(NULL)); 00106 } else { 00107 snprintf(tmp, sizeof(tmp), "%c,%10d,%s", event, (int)time(NULL), data); 00108 } 00109 00110 fprintf(handle, "%s\n", tmp); 00111 if (option_debug) 00112 ast_chan_log(LOG_DEBUG, chan, "sent '%s'\n", tmp); 00113 }
static int unload_module | ( | void | ) | [static] |
Definition at line 662 of file app_externalivr.c.
References ast_unregister_application().
00663 { 00664 return ast_unregister_application(app); 00665 }
struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "External IVR Interface Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = "068e67f60f50dd9ee86464c05884a49d" , .load = load_module, .unload = unload_module, } [static] |
Definition at line 672 of file app_externalivr.c.
const char* app = "ExternalIVR" [static] |
Definition at line 56 of file app_externalivr.c.
const struct ast_module_info* ast_module_info = &__mod_info [static] |
Definition at line 672 of file app_externalivr.c.
const char* descrip [static] |
Definition at line 60 of file app_externalivr.c.
struct ast_generator gen [static] |
Definition at line 229 of file app_externalivr.c.
Referenced by app_exec(), ast_activate_generator(), reload_config(), and set_config().
const char* synopsis = "Interfaces with an external IVR application" [static] |
Definition at line 58 of file app_externalivr.c.