97 static const char app[] =
"ExternalIVR";
100 #define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, channel->name , ## __VA_ARGS__)
103 #define EIVR_CMD_APND 'A'
104 #define EIVR_CMD_DTMF 'D'
105 #define EIVR_CMD_EXIT 'E'
106 #define EIVR_CMD_GET 'G'
107 #define EIVR_CMD_HGUP 'H'
108 #define EIVR_CMD_LOG 'L'
109 #define EIVR_CMD_OPT 'O'
110 #define EIVR_CMD_PARM 'P'
111 #define EIVR_CMD_SQUE 'S'
112 #define EIVR_CMD_ANS 'T'
113 #define EIVR_CMD_SVAR 'V'
114 #define EIVR_CMD_XIT 'X'
137 int abort_current_sound;
139 int option_autoclear;
145 struct ivr_localuser *
u;
152 int *eivr_events_fd,
int *eivr_commands_fd,
int *eivr_errors_fd,
174 struct ivr_localuser *u = params;
206 struct ivr_localuser *u = state->
u;
207 char *file_to_stream;
218 file_to_stream =
"silence/10";
241 struct ivr_localuser *u = state->
u;
306 char *
inbuf, *variable;
313 for (j = 1, inbuf = data; ; j++) {
314 variable =
strsep(&inbuf,
",");
315 if (variable == NULL) {
316 int outstrlen = strlen(outbuf);
317 if (outstrlen && outbuf[outstrlen - 1] ==
',') {
318 outbuf[outstrlen - 1] = 0;
340 for (variable =
strsep(&inbuf,
","); variable; variable =
strsep(&inbuf,
",")) {
341 ast_debug(1,
"Setting up a variable: %s\n", variable);
343 value = strchr(variable,
'=');
357 int dinterval = 0, duration = 0;
373 ast_verb(4,
"Sending DTMF: %s %d %d\n",
args.digits, dinterval <= 0 ? 250 : dinterval, duration);
381 if (!(entry =
ast_calloc(1,
sizeof(*entry) + strlen(filename) + 10)))
394 int child_stdin[2] = { -1, -1 };
395 int child_stdout[2] = { -1, -1 };
396 int child_stderr[2] = { -1, -1 };
401 char *port_str = NULL;
405 struct ivr_localuser foo = {
410 struct ivr_localuser *u = &foo;
414 char *s, **app_args, *e;
436 ast_verb(4,
"ExternalIVR received application and arguments: %s\n", eivr_args.application);
437 ast_verb(4,
"ExternalIVR received options: %s\n", eivr_args.options);
440 if ((s = strchr(eivr_args.application,
'('))) {
442 if ((e = strrchr(s,
')'))) {
451 app_args = application_args.argv;
455 for (j = 0; application_args.cmd[j] != NULL; j++) {
456 ast_str_append(&comma_delim_args, 0,
"%s%s", j == 0 ?
"" :
",", application_args.cmd[j]);
460 if (eivr_args.options && (s = strchr(eivr_args.options,
','))) {
465 ast_verb(4,
"Parsing options from: [%s]\n", eivr_args.options);
471 ast_verb(4,
"ignore_hangup is set\n");
478 ast_verb(3,
"Answering channel and starting generator\n");
481 ast_chan_log(
LOG_ERROR, chan,
"Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
494 if (!strncmp(app_args[0],
"ivr://", 6)) {
500 struct sockaddr_in remote_address_tmp;
503 ast_debug(1,
"Parsing hostname:port for socket connect from \"%s\"\n", app_args[0]);
505 if ((port_str = strchr(hostname,
':')) != NULL) {
508 port = atoi(port_str);
515 remote_address_tmp.sin_family = AF_INET;
516 remote_address_tmp.sin_port = htons(port);
517 memcpy(&remote_address_tmp.sin_addr.s_addr, hp.
hp.h_addr, hp.
hp.h_length);
522 res =
eivr_comm(chan, u, &ser->
fd, &ser->
fd, NULL, comma_delim_args, flags);
525 if (pipe(child_stdin)) {
529 if (pipe(child_stdout)) {
533 if (pipe(child_stderr)) {
549 dup2(child_stdin[0], STDIN_FILENO);
550 dup2(child_stdout[1], STDOUT_FILENO);
551 dup2(child_stderr[1], STDERR_FILENO);
553 execv(app_args[0], app_args);
554 fprintf(stderr,
"Failed to execute '%s': %s\n", app_args[0], strerror(
errno));
558 close(child_stdin[0]);
560 close(child_stdout[1]);
561 child_stdout[1] = -1;
562 close(child_stderr[1]);
563 child_stderr[1] = -1;
564 res =
eivr_comm(chan, u, &child_stdin[1], &child_stdout[0], &child_stderr[0], comma_delim_args, flags);
572 if (child_stdin[0] > -1) {
573 close(child_stdin[0]);
575 if (child_stdin[1] > -1) {
576 close(child_stdin[1]);
578 if (child_stdout[0] > -1) {
579 close(child_stdout[0]);
581 if (child_stdout[1] > -1) {
582 close(child_stdout[1]);
584 if (child_stderr[0] > -1) {
585 close(child_stderr[0]);
587 if (child_stderr[1] > -1) {
588 close(child_stderr[1]);
600 int *eivr_events_fd,
int *eivr_commands_fd,
int *eivr_errors_fd,
608 int waitfds[2] = { *eivr_commands_fd, (eivr_errors_fd) ? *eivr_errors_fd : -1 };
611 int test_available_fd = -1;
612 int hangup_info_sent = 0;
614 FILE *eivr_commands = NULL;
615 FILE *eivr_errors = NULL;
616 FILE *eivr_events = NULL;
618 if (!(eivr_events = fdopen(*eivr_events_fd,
"w"))) {
622 if (!(eivr_commands = fdopen(*eivr_commands_fd,
"r"))) {
626 if (eivr_errors_fd) {
627 if (!(eivr_errors = fdopen(*eivr_errors_fd,
"r"))) {
633 test_available_fd = open(
"/dev/null", O_RDONLY);
635 setvbuf(eivr_events, NULL, _IONBF, 0);
636 setvbuf(eivr_commands, NULL, _IONBF, 0);
638 setvbuf(eivr_errors, NULL, _IONBF, 0);
648 ast_verb(3,
"Got check_hangup, but ignore_hangup set so sending 'I' command\n");
650 hangup_info_sent = 1;
663 rchan =
ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd) ? 2 : 1, &exception, &ready_fd, &ms);
702 ast_verb(3,
"Got AST_CONTROL_HANGUP\n");
711 }
else if (ready_fd == *eivr_commands_fd) {
714 if (exception || (dup2(*eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) {
719 if (!fgets(input,
sizeof(input), eivr_commands)) {
724 ast_verb(4,
"got command '%s'\n", input);
726 if (strlen(input) < 3) {
734 ast_verb(4,
"Sending DTMF: %s\n", &input[2]);
737 ast_verb(3,
"Answering channel if needed and starting generator\n");
740 ast_chan_log(
LOG_WARNING, chan,
"Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
808 ast_verb(4,
"Retriving Variables from channel: %s\n", &input[2]);
812 ast_verb(4,
"Setting Variables in channel: %s\n", &input[2]);
836 if (!strcasecmp(&input[2],
"autoclear"))
838 else if (!strcasecmp(&input[2],
"noautoclear"))
843 }
else if (eivr_errors_fd && (ready_fd == *eivr_errors_fd)) {
846 if (exception || feof(eivr_errors)) {
850 if (fgets(input,
sizeof(input), eivr_errors)) {
853 }
else if ((ready_fd < 0) && ms) {
863 if (test_available_fd > -1) {
864 close(test_available_fd);
868 *eivr_events_fd = -1;
871 fclose(eivr_commands);
872 *eivr_commands_fd = -1;
876 *eivr_errors_fd = -1;
union ast_frame_subclass subclass
enum sip_cc_notify_state state
#define ast_channel_lock(chan)
Main Channel structure associated with a channel.
#define AST_MODULE_INFO_STANDARD(keystr, desc)
#define AST_LIST_LOCK(head)
Locks a list.
Asterisk locking-related definitions:
Asterisk main include file. File version handling, generic pbx functions.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
char * strsep(char **str, const char *delims)
static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
static void * gen_alloc(struct ast_channel *chan, void *params)
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 struct ast_str *args, const struct ast_flags flags)
struct ivr_localuser::playlist playlist
#define ast_test_flag(p, flag)
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)
int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen defunit)
Common routine to parse time lengths, with optional time unit specifier.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define ast_chan_log(level, channel, format,...)
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
int eivr_connect_socket(struct ast_channel *chan, const char *host, int port)
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
struct playlist_entry * current
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
struct ast_str * ast_str_create(size_t init_len)
Create a malloc'ed dynamic length string.
arguments for the accepting thread
struct ast_filestream * ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
Opens stream for use in seeking, playing.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define ast_str_alloca(init_len)
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
static int load_module(void)
Generic support for tcp/tls servers in Asterisk.
static int input(yyscan_t yyscanner)
int ast_unregister_application(const char *app)
Unregister an application.
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **chan, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
#define ast_verb(level,...)
static struct ast_frame * gen_readframe(struct gen_state *state)
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static struct ast_app_option app_opts[128]
#define ast_debug(level,...)
Log a DEBUG message.
General Asterisk PBX channel definitions.
#define ast_sockaddr_from_sin(addr, sin)
Converts a struct sockaddr_in to a struct ast_sockaddr.
static struct ast_generator gen
static int gen_nextfile(struct gen_state *state)
static force_inline int attribute_pure ast_strlen_zero(const char *s)
struct playlist_entry::@15 list
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
static void ast_eivr_senddtmf(struct ast_channel *chan, char *vdata)
struct ast_sockaddr remote_address
#define ao2_ref(o, delta)
A set of macros to manage forward-linked lists.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Core PBX routines and definitions.
static void gen_closestream(struct gen_state *state)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
int ast_set_priority(int)
We set ourselves to a high priority, that we might pre-empt everything else. If your PBX has heavy ac...
static int app_exec(struct ast_channel *chan, const char *data)
static int unload_module(void)
static void gen_release(struct ast_channel *chan, void *data)
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
struct ast_filestream * stream
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
enum ast_channel_state _state
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define ast_channel_unlock(chan)
void *(* alloc)(struct ast_channel *chan, void *params)
int ast_closestream(struct ast_filestream *f)
Closes a stream.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
int ast_write(struct ast_channel *chan, struct ast_frame *frame)
Write a frame to a channel This function writes the given frame to the indicated channel.
Structure used to handle boolean flags.
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
void ast_deactivate_generator(struct ast_channel *chan)
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Thread-safe gethostbyname function to use in Asterisk.
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
int ast_answer(struct ast_channel *chan)
Answer a channel.
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
Data structure associated with a single frame of data.
struct ivr_localuser::finishlist finishlist
struct ast_tcptls_session_instance * ast_tcptls_client_start(struct ast_tcptls_session_instance *tcptls_session)
attempts to connect and start tcptls session, on error the tcptls_session's ref count is decremented...
#define AST_APP_ARG(name)
Define an application argument.
enum ast_frame_type frametype
static void send_eivr_event(FILE *handle, const char event, const char *data, const struct ast_channel *chan)
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
Send DTMF to a channel.
#define AST_LIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD.
struct ast_filestream * stream
#define ASTERISK_GPL_KEY
The text the key() function should return.
Asterisk module definitions.
union ast_frame::@172 data
static void ast_eivr_setvariable(struct ast_channel *chan, char *data)
static struct playlist_entry * make_entry(const char *filename)
const ast_string_field language
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
#define ast_opt_high_priority
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
static char hostname[MAXHOSTNAMELEN]
struct ast_channel * chan