98static const char app[] = 
"ExternalIVR";
 
  101#define ast_chan_log(level, channel, format, ...) ast_log(level, "%s: " format, ast_channel_name(channel) , ## __VA_ARGS__) 
  104#define EIVR_CMD_APND 'A'  
  105#define EIVR_CMD_DTMF 'D'  
  106#define EIVR_CMD_EXIT 'E'  
  107#define EIVR_CMD_GET  'G'  
  108#define EIVR_CMD_HGUP 'H'  
  109#define EIVR_CMD_IRPT 'I'  
  110#define EIVR_CMD_LOG  'L'  
  111#define EIVR_CMD_OPT  'O'  
  112#define EIVR_CMD_PARM 'P'  
  113#define EIVR_CMD_SQUE 'S'  
  114#define EIVR_CMD_ANS  'T'  
  115#define EIVR_CMD_SVAR 'V'  
  116#define EIVR_CMD_XIT  'X'  
  118#define EXTERNALIVR_PORT 2949 
  213    char *file_to_stream;
 
  219    while (!
state->stream) {
 
  221        if (
state->current) {
 
  222            file_to_stream = 
state->current->filename;
 
  224            file_to_stream = 
"silence/10";
 
  241    return (!
state->stream);
 
 
  258        if (
state->current) {
 
 
  284    while (
state->sample_queue > 0) {
 
 
  312    char *
inbuf, *variable;
 
  319    for (j = 1, 
inbuf = data; ; j++) {
 
  321        if (variable == 
NULL) {
 
  322            int outstrlen = strlen(outbuf);
 
  323            if (outstrlen && outbuf[outstrlen - 1] == 
',') {
 
  324                outbuf[outstrlen - 1] = 0;
 
 
  347        ast_debug(1, 
"Setting up a variable: %s\n", variable);
 
  349        value = strchr(variable, 
'=');
 
 
  363    int dinterval = 0, duration = 0;
 
  379    ast_verb(4, 
"Sending DTMF: %s %d %d\n", 
args.digits, dinterval <= 0 ? 250 : dinterval, duration);
 
 
  400    int child_stdin[2] = { -1, -1 };
 
  401    int child_stdout[2] = { -1, -1 };
 
  402    int child_stderr[2] = { -1, -1 };
 
  404        *stream_stderr = 
NULL;
 
  414        .playing_silence = 1,
 
  420    char *s, **app_args, *e;
 
  428#define MAX_EIVR_APPLICATION_ARGS 32 
  445    ast_verb(4, 
"ExternalIVR received application and arguments: %s\n", eivr_args.application);
 
  446    ast_verb(4, 
"ExternalIVR received options: %s\n", eivr_args.options);
 
  449    if ((s = strchr(eivr_args.application, 
'('))) {
 
  451        if ((e = strrchr(s, 
')'))) {
 
  460    app_args = application_args.argv;
 
  465        ast_str_append(&comma_delim_args, 0, 
"%s%s", j == 0 ? 
"" : 
",", application_args.cmd[j]);
 
  469    if (eivr_args.options && (s = strchr(eivr_args.options, 
','))) {
 
  474    ast_verb(4, 
"Parsing options from: [%s]\n", eivr_args.options);
 
  480        ast_verb(4, 
"ignore_hangup is set\n");
 
  487        ast_verb(3, 
"Answering channel and starting generator\n");
 
  490                ast_chan_log(
LOG_ERROR, chan, 
"Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
 
  503    if (!strncmp(app_args[0], 
"ivr://", 
sizeof(
"ivr://") - 1)) {
 
  509        int num_addrs = 0, i = 0;
 
  510        char *host = app_args[0] + 
sizeof(
"ivr://") - 1;
 
  513        ast_debug(1, 
"Parsing hostname/port for socket connect from \"%s\"\n", host);
 
  520        for (i = 0; i < num_addrs; i++) {
 
  534        if (i == num_addrs) {
 
  542        if (pipe(child_stdin)) {
 
  546        if (pipe(child_stdout)) {
 
  550        if (pipe(child_stderr)) {
 
  566            dup2(child_stdin[0], STDIN_FILENO);
 
  567            dup2(child_stdout[1], STDOUT_FILENO);
 
  568            dup2(child_stderr[1], STDERR_FILENO);
 
  570            execv(app_args[0], app_args);
 
  571            fprintf(stderr, 
"Failed to execute '%s': %s\n", app_args[0], strerror(
errno));
 
  575            close(child_stdin[0]);
 
  577            close(child_stdout[1]);
 
  578            child_stdout[1] = -1;
 
  579            close(child_stderr[1]);
 
  580            child_stderr[1] = -1;
 
  586            res = 
eivr_comm(chan, u, stream_stdin, stream_stdout, stream_stderr, comma_delim_args, flags);
 
  603    if (child_stdin[0] > -1) {
 
  604        close(child_stdin[0]);
 
  606    if (child_stdin[1] > -1) {
 
  607        close(child_stdin[1]);
 
  609    if (child_stdout[0] > -1) {
 
  610        close(child_stdout[0]);
 
  612    if (child_stdout[1] > -1) {
 
  613        close(child_stdout[1]);
 
  615    if (child_stderr[0] > -1) {
 
  616        close(child_stderr[0]);
 
  618    if (child_stderr[1] > -1) {
 
  619        close(child_stderr[1]);
 
 
  646    int hangup_info_sent = 0;
 
  658                ast_verb(3, 
"Got check_hangup, but ignore_hangup set so sending 'I' command\n");
 
  660                hangup_info_sent = 1;
 
  673        rchan = 
ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors) ? 2 : 1, &exception, &ready_fd, &ms);
 
  712                ast_verb(3, 
"Got AST_CONTROL_HANGUP\n");
 
  721        } 
else if (ready_fd == waitfds[0]) {
 
  737            ast_verb(4, 
"got command '%s'\n", input);
 
  739            if (strlen(input) < 3) {
 
  747                ast_verb(4, 
"Sending DTMF: %s\n", &input[2]);
 
  750                ast_verb(3, 
"Answering channel if needed and starting generator\n");
 
  753                        ast_chan_log(
LOG_WARNING, chan, 
"Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
 
  843                ast_verb(4, 
"Retrieving Variables from channel: %s\n", &input[2]);
 
  847                ast_verb(4, 
"Setting Variables in channel: %s\n", &input[2]);
 
  871                if (!strcasecmp(&input[2], 
"autoclear"))
 
  873                else if (!strcasecmp(&input[2], 
"noautoclear"))
 
  878        } 
else if (ready_fd == waitfds[1]) {
 
  891        } 
else if ((ready_fd < 0) && ms) {
 
 
static const char app_exec[]
static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
static int eivr_comm(struct ast_channel *chan, struct ivr_localuser *u, struct ast_iostream *eivr_events, struct ast_iostream *eivr_commands, struct ast_iostream *eivr_errors, const struct ast_str *args, const struct ast_flags flags)
static void send_eivr_event(struct ast_iostream *stream, const char event, const char *data, const struct ast_channel *chan)
static struct playlist_entry * make_entry(const char *filename)
static struct ast_frame * gen_readframe(struct gen_state *state)
#define ast_chan_log(level, channel, format,...)
static void ast_eivr_setvariable(struct ast_channel *chan, char *data)
static const struct ast_app_option app_opts[128]
static int gen_nextfile(struct gen_state *state)
static void gen_release(struct ast_channel *chan, void *data)
static struct ast_generator gen
static int load_module(void)
static void * gen_alloc(struct ast_channel *chan, void *params)
static int unload_module(void)
static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)
static void ast_eivr_senddtmf(struct ast_channel *chan, char *vdata)
static void gen_closestream(struct gen_state *state)
#define MAX_EIVR_APPLICATION_ARGS
char * strsep(char **str, const char *delims)
Asterisk main include file. File version handling, generic pbx functions.
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...
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_calloc(num, len)
A wrapper for calloc()
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
General Asterisk PBX channel definitions.
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
struct ast_channel * ast_waitfor_nandfds(struct ast_channel **c, int n, int *fds, int nfds, int *exception, int *outfd, int *ms)
Waits for activity on a group of channels.
#define ast_channel_lock(chan)
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
void ast_deactivate_generator(struct ast_channel *chan)
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.
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
const char * ast_channel_language(const struct ast_channel *chan)
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_answer(struct ast_channel *chan)
Answer a channel.
#define ast_channel_unlock(chan)
ast_channel_state
ast_channel states
Generic File Format Support. Should be included by clients of the file handling routines....
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.
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
int ast_closestream(struct ast_filestream *f)
Closes a stream.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
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_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
Send a string of DTMF digits to a channel.
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.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
ssize_t ast_iostream_gets(struct ast_iostream *stream, char *buffer, size_t size)
Read a LF-terminated string from an iostream.
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t count)
Write data to an iostream.
int ast_iostream_get_fd(struct ast_iostream *stream)
Get an iostream's file descriptor.
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
A set of macros to manage forward-linked lists.
#define AST_LIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_LOCK(head)
Locks a list.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
#define AST_LIST_HEAD(name, type)
Defines a structure to be used to hold a list of specified type.
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Asterisk locking-related definitions:
Asterisk module definitions.
#define ASTERISK_GPL_KEY
The text the key() function should return.
int ast_unregister_application(const char *app)
Unregister an application.
#define AST_MODULE_INFO_STANDARD_EXTENDED(keystr, desc)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
int ast_sockaddr_resolve(struct ast_sockaddr **addrs, const char *str, int flags, int family)
Parses a string with an IPv4 or IPv6 address and place results into an array.
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
#define ast_opt_high_priority
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
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.
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
#define ast_str_alloca(init_len)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Main Channel structure associated with a channel.
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Structure used to handle boolean flags.
Data structure associated with a single frame of data.
struct ast_frame_subclass subclass
enum ast_frame_type frametype
union ast_frame::@239 data
void *(* alloc)(struct ast_channel *chan, void *params)
Socket address structure.
Support for dynamic strings.
arguments for the accepting thread
struct ast_sockaddr remote_address
describes a server instance
struct ast_iostream * stream
struct ast_filestream * stream
struct playlist_entry * current
struct ast_channel * chan
struct ivr_localuser::playlist playlist
struct ivr_localuser::finishlist finishlist
struct playlist_entry::@22 list
Generic support for tcp/tls servers in Asterisk.
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
Creates a client connection's ast_tcptls_session_instance.
struct ast_tcptls_session_instance * ast_tcptls_client_start(struct ast_tcptls_session_instance *tcptls_session)
Attempt to connect and start a tcptls session.
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
#define ast_test_flag(p, flag)