Asterisk - The Open Source Telephony Project GIT-master-b023714
Loading...
Searching...
No Matches
Data Structures | Macros | Enumerations | Functions | Variables
app_externalivr.c File Reference

External IVR application interface. More...

#include "asterisk.h"
#include <signal.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"
#include "asterisk/tcptls.h"
#include "asterisk/astobj2.h"
Include dependency graph for app_externalivr.c:

Go to the source code of this file.

Data Structures

struct  ivr_localuser::finishlist
 
struct  gen_state
 
struct  ivr_localuser
 
struct  ivr_localuser::playlist
 
struct  playlist_entry
 

Macros

#define ast_chan_log(level, channel, format, ...)   ast_log(level, "%s: " format, ast_channel_name(channel) , ## __VA_ARGS__)
 
#define EIVR_CMD_ANS   'T' /* answer channel */
 
#define EIVR_CMD_APND   'A' /* append to prompt queue */
 
#define EIVR_CMD_DTMF   'D' /* send DTMF */
 
#define EIVR_CMD_EXIT   'E' /* exit */
 
#define EIVR_CMD_GET   'G' /* get channel varable(s) */
 
#define EIVR_CMD_HGUP   'H' /* hangup */
 
#define EIVR_CMD_IRPT   'I' /* interrupt */
 
#define EIVR_CMD_LOG   'L' /* log message */
 
#define EIVR_CMD_OPT   'O' /* option */
 
#define EIVR_CMD_PARM   'P' /* return supplied params */
 
#define EIVR_CMD_SQUE   'S' /* (re)set prompt queue */
 
#define EIVR_CMD_SVAR   'V' /* set channel varable(s) */
 
#define EIVR_CMD_XIT   'X' /* exit **depricated** */
 
#define EXTERNALIVR_PORT   2949
 
#define MAX_EIVR_APPLICATION_ARGS   32
 

Enumerations

enum  options_flags { noanswer = (1 << 0) , ignore_hangup = (1 << 1) , run_dead = (1 << 2) }
 

Functions

static int app_exec (struct ast_channel *chan, const char *data)
 
static void ast_eivr_getvariable (struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
 
static void ast_eivr_senddtmf (struct ast_channel *chan, char *vdata)
 
static void ast_eivr_setvariable (struct ast_channel *chan, char *data)
 
 AST_MODULE_INFO_STANDARD_EXTENDED (ASTERISK_GPL_KEY, "External IVR Interface Application")
 
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 * 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_framegen_readframe (struct gen_state *state)
 
static void gen_release (struct ast_channel *chan, void *data)
 
static int load_module (void)
 
static struct playlist_entrymake_entry (const char *filename)
 
static void send_eivr_event (struct ast_iostream *stream, const char event, const char *data, const struct ast_channel *chan)
 
static int unload_module (void)
 

Variables

static const char app [] = "ExternalIVR"
 
static const struct ast_app_option app_opts [128] = { [ 'n' ] = { .flag = noanswer }, [ 'i' ] = { .flag = ignore_hangup }, [ 'd' ] = { .flag = run_dead }, }
 
static struct ast_generator gen
 

Detailed Description

External IVR application interface.

Author
Kevin P. Fleming kpfle.nosp@m.ming.nosp@m.@digi.nosp@m.um.c.nosp@m.om
Note
Portions taken from the file-based music-on-hold work created by Anthony Minessale II in res_musiconhold.c

Definition in file app_externalivr.c.

Macro Definition Documentation

◆ ast_chan_log

#define ast_chan_log (   level,
  channel,
  format,
  ... 
)    ast_log(level, "%s: " format, ast_channel_name(channel) , ## __VA_ARGS__)

Definition at line 101 of file app_externalivr.c.

◆ EIVR_CMD_ANS

#define EIVR_CMD_ANS   'T' /* answer channel */

Definition at line 114 of file app_externalivr.c.

◆ EIVR_CMD_APND

#define EIVR_CMD_APND   'A' /* append to prompt queue */

Definition at line 104 of file app_externalivr.c.

◆ EIVR_CMD_DTMF

#define EIVR_CMD_DTMF   'D' /* send DTMF */

Definition at line 105 of file app_externalivr.c.

◆ EIVR_CMD_EXIT

#define EIVR_CMD_EXIT   'E' /* exit */

Definition at line 106 of file app_externalivr.c.

◆ EIVR_CMD_GET

#define EIVR_CMD_GET   'G' /* get channel varable(s) */

Definition at line 107 of file app_externalivr.c.

◆ EIVR_CMD_HGUP

#define EIVR_CMD_HGUP   'H' /* hangup */

Definition at line 108 of file app_externalivr.c.

◆ EIVR_CMD_IRPT

#define EIVR_CMD_IRPT   'I' /* interrupt */

Definition at line 109 of file app_externalivr.c.

◆ EIVR_CMD_LOG

#define EIVR_CMD_LOG   'L' /* log message */

Definition at line 110 of file app_externalivr.c.

◆ EIVR_CMD_OPT

#define EIVR_CMD_OPT   'O' /* option */

Definition at line 111 of file app_externalivr.c.

◆ EIVR_CMD_PARM

#define EIVR_CMD_PARM   'P' /* return supplied params */

Definition at line 112 of file app_externalivr.c.

◆ EIVR_CMD_SQUE

#define EIVR_CMD_SQUE   'S' /* (re)set prompt queue */

Definition at line 113 of file app_externalivr.c.

◆ EIVR_CMD_SVAR

#define EIVR_CMD_SVAR   'V' /* set channel varable(s) */

Definition at line 115 of file app_externalivr.c.

◆ EIVR_CMD_XIT

#define EIVR_CMD_XIT   'X' /* exit **depricated** */

Definition at line 116 of file app_externalivr.c.

◆ EXTERNALIVR_PORT

#define EXTERNALIVR_PORT   2949

Definition at line 118 of file app_externalivr.c.

◆ MAX_EIVR_APPLICATION_ARGS

#define MAX_EIVR_APPLICATION_ARGS   32

Enumeration Type Documentation

◆ options_flags

Enumerator
noanswer 
ignore_hangup 
run_dead 

Definition at line 120 of file app_externalivr.c.

120 {
121 noanswer = (1 << 0),
122 ignore_hangup = (1 << 1),
123 run_dead = (1 << 2),
124};
@ run_dead
@ ignore_hangup
@ noanswer

Function Documentation

◆ app_exec()

static int app_exec ( struct ast_channel chan,
const char *  data 
)
static

Definition at line 395 of file app_externalivr.c.

396{
397 struct ast_flags flags = { 0, };
398 char *opts[0];
399 struct playlist_entry *entry;
400 int child_stdin[2] = { -1, -1 };
401 int child_stdout[2] = { -1, -1 };
402 int child_stderr[2] = { -1, -1 };
405 int res = -1;
406 int pid;
407
408 struct ast_tcptls_session_instance *ser = NULL;
409
410 struct ivr_localuser foo = {
412 .finishlist = AST_LIST_HEAD_INIT_VALUE,
413 .gen_active = 0,
414 .playing_silence = 1,
415 };
416 struct ivr_localuser *u = &foo;
417
418 char *buf;
419 int j;
420 char *s, **app_args, *e;
421 struct ast_str *comma_delim_args = ast_str_alloca(100);
422
423 AST_DECLARE_APP_ARGS(eivr_args,
424 AST_APP_ARG(application);
426 );
427
428#define MAX_EIVR_APPLICATION_ARGS 32
429
430 AST_DECLARE_APP_ARGS(application_args,
432 );
433
434 u->abort_current_sound = 0;
435 u->chan = chan;
436
437 if (ast_strlen_zero(data)) {
438 ast_log(LOG_ERROR, "ExternalIVR requires a command to execute\n");
439 goto exit;
440 }
441
442 buf = ast_strdupa(data);
443 AST_STANDARD_APP_ARGS(eivr_args, buf);
444
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);
447
448 /* Parse out any application arguments */
449 if ((s = strchr(eivr_args.application, '('))) {
450 s[0] = ',';
451 if ((e = strrchr(s, ')'))) {
452 *e = '\0';
453 } else {
454 ast_log(LOG_ERROR, "Parse error, missing closing parenthesis\n");
455 goto exit;
456 }
457 }
458
459 AST_STANDARD_APP_ARGS(application_args, eivr_args.application);
460 app_args = application_args.argv;
461
462 /* Put the application + the arguments in a , delimited list */
463 ast_str_reset(comma_delim_args);
464 for (j = 0; j < MAX_EIVR_APPLICATION_ARGS && application_args.cmd[j]; j++) {
465 ast_str_append(&comma_delim_args, 0, "%s%s", j == 0 ? "" : ",", application_args.cmd[j]);
466 }
467
468 /* Get rid of any extraneous arguments */
469 if (eivr_args.options && (s = strchr(eivr_args.options, ','))) {
470 *s = '\0';
471 }
472
473 /* Parse the ExternalIVR() arguments */
474 ast_verb(4, "Parsing options from: [%s]\n", eivr_args.options);
475 ast_app_parse_options(app_opts, &flags, opts, eivr_args.options);
476 if (ast_test_flag(&flags, noanswer)) {
477 ast_verb(4, "noanswer is set\n");
478 }
479 if (ast_test_flag(&flags, ignore_hangup)) {
480 ast_verb(4, "ignore_hangup is set\n");
481 }
482 if (ast_test_flag(&flags, run_dead)) {
483 ast_verb(4, "run_dead is set\n");
484 }
485
486 if (!(ast_test_flag(&flags, noanswer))) {
487 ast_verb(3, "Answering channel and starting generator\n");
488 if (ast_channel_state(chan) != AST_STATE_UP) {
489 if (ast_test_flag(&flags, run_dead)) {
490 ast_chan_log(LOG_ERROR, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
491 goto exit;
492 }
493 ast_answer(chan);
494 }
495 if (ast_activate_generator(chan, &gen, u) < 0) {
496 ast_chan_log(LOG_ERROR, chan, "Failed to activate generator\n");
497 goto exit;
498 } else {
499 u->gen_active = 1;
500 }
501 }
502
503 if (!strncmp(app_args[0], "ivr://", sizeof("ivr://") - 1)) {
504 struct ast_tcptls_session_args ivr_desc = {
505 .accept_fd = -1,
506 .name = "IVR",
507 };
508 struct ast_sockaddr *addrs;
509 int num_addrs = 0, i = 0;
510 char *host = app_args[0] + sizeof("ivr://") - 1;
511
512 /* Communicate through socket to server */
513 ast_debug(1, "Parsing hostname/port for socket connect from \"%s\"\n", host);
514
515 if (!(num_addrs = ast_sockaddr_resolve(&addrs, host, 0, AST_AF_UNSPEC))) {
516 ast_chan_log(LOG_ERROR, chan, "Unable to locate host '%s'\n", host);
517 goto exit;
518 }
519
520 for (i = 0; i < num_addrs; i++) {
521 if (!ast_sockaddr_port(&addrs[i])) {
522 /* Default port if not specified */
524 }
525 ast_sockaddr_copy(&ivr_desc.remote_address, &addrs[i]);
526 if (!(ser = ast_tcptls_client_create(&ivr_desc)) || !(ser = ast_tcptls_client_start(ser))) {
527 continue;
528 }
529 break;
530 }
531
532 ast_free(addrs);
533
534 if (i == num_addrs) {
535 ast_chan_log(LOG_ERROR, chan, "Could not connect to any host. ExternalIVR failed.\n");
536 goto exit;
537 }
538
539 res = eivr_comm(chan, u, ser->stream, ser->stream, NULL, comma_delim_args, flags);
540
541 } else {
542 if (pipe(child_stdin)) {
543 ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child input: %s\n", strerror(errno));
544 goto exit;
545 }
546 if (pipe(child_stdout)) {
547 ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child output: %s\n", strerror(errno));
548 goto exit;
549 }
550 if (pipe(child_stderr)) {
551 ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
552 goto exit;
553 }
554
555 pid = ast_safe_fork(0);
556 if (pid < 0) {
557 ast_log(LOG_ERROR, "Failed to fork(): %s\n", strerror(errno));
558 goto exit;
559 }
560
561 if (!pid) {
562 /* child process */
565
566 dup2(child_stdin[0], STDIN_FILENO);
567 dup2(child_stdout[1], STDOUT_FILENO);
568 dup2(child_stderr[1], STDERR_FILENO);
569 ast_close_fds_above_n(STDERR_FILENO);
570 execv(app_args[0], app_args);
571 fprintf(stderr, "Failed to execute '%s': %s\n", app_args[0], strerror(errno));
572 _exit(1);
573 } else {
574 /* parent process */
575 close(child_stdin[0]);
576 child_stdin[0] = -1;
577 close(child_stdout[1]);
578 child_stdout[1] = -1;
579 close(child_stderr[1]);
580 child_stderr[1] = -1;
581
582 stream_stdin = ast_iostream_from_fd(&child_stdin[1]);
583 stream_stdout = ast_iostream_from_fd(&child_stdout[0]);
584 stream_stderr = ast_iostream_from_fd(&child_stderr[0]);
585
586 res = eivr_comm(chan, u, stream_stdin, stream_stdout, stream_stderr, comma_delim_args, flags);
587 }
588 }
589
590 exit:
591 if (u->gen_active) {
593 }
594 if (stream_stdin) {
595 ast_iostream_close(stream_stdin);
596 }
597 if (stream_stdout) {
598 ast_iostream_close(stream_stdout);
599 }
600 if (stream_stderr) {
601 ast_iostream_close(stream_stderr);
602 }
603 if (child_stdin[0] > -1) {
604 close(child_stdin[0]);
605 }
606 if (child_stdin[1] > -1) {
607 close(child_stdin[1]);
608 }
609 if (child_stdout[0] > -1) {
610 close(child_stdout[0]);
611 }
612 if (child_stdout[1] > -1) {
613 close(child_stdout[1]);
614 }
615 if (child_stderr[0] > -1) {
616 close(child_stderr[0]);
617 }
618 if (child_stderr[1] > -1) {
619 close(child_stderr[1]);
620 }
621 if (ser) {
622 ao2_ref(ser, -1);
623 }
624 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
625 ast_free(entry);
626 }
627 return res;
628}
#define EXTERNALIVR_PORT
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)
#define ast_chan_log(level, channel, format,...)
static const struct ast_app_option app_opts[128]
static struct ast_generator gen
#define MAX_EIVR_APPLICATION_ARGS
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...
Definition asterisk.c:1853
#define ast_free(a)
Definition astmm.h:180
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition astmm.h:298
#define ast_log
Definition astobj2.c:42
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
Definition astobj2.h:459
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition channel.c:2923
void ast_deactivate_generator(struct ast_channel *chan)
Definition channel.c:2865
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition channel.c:2778
ast_channel_state
ast_channel states
@ AST_STATE_UP
char buf[BUFSIZE]
Definition eagi_proxy.c:66
#define AST_APP_ARG(name)
Define an application argument.
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child.
Definition main/app.c:3207
#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.
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.
Definition main/app.c:3066
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition main/app.c:3202
#define ast_debug(level,...)
Log a DEBUG message.
#define LOG_ERROR
#define ast_verb(level,...)
struct ast_iostream * ast_iostream_from_fd(int *fd)
Create an iostream from a file descriptor.
Definition iostream.c:611
int ast_iostream_close(struct ast_iostream *stream)
Close an iostream.
Definition iostream.c:539
#define AST_LIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
int errno
@ AST_AF_UNSPEC
Definition netsock2.h:54
#define ast_sockaddr_port(addr)
Get the port number of a socket address.
Definition netsock2.h:517
static void ast_sockaddr_copy(struct ast_sockaddr *dst, const struct ast_sockaddr *src)
Copies the data from one ast_sockaddr to another.
Definition netsock2.h:167
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.
Definition netsock2.c:280
#define ast_sockaddr_set_port(addr, port)
Sets the port number of a socket address.
Definition netsock2.h:532
#define ast_opt_high_priority
Definition options.h:122
#define NULL
Definition resample.c:96
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
Definition strings.h:1139
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition strings.h:65
#define ast_str_alloca(init_len)
Definition strings.h:848
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
Definition strings.h:693
Structure used to handle boolean flags.
Definition utils.h:217
unsigned int flags
Definition utils.h:218
struct timeval start
Definition iostream.c:41
Socket address structure.
Definition netsock2.h:97
Support for dynamic strings.
Definition strings.h:623
arguments for the accepting thread
Definition tcptls.h:130
struct ast_sockaddr remote_address
Definition tcptls.h:133
describes a server instance
Definition tcptls.h:151
struct ast_iostream * stream
Definition tcptls.h:162
struct ast_channel * chan
struct ivr_localuser::playlist playlist
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
Creates a client connection's ast_tcptls_session_instance.
Definition tcptls.c:686
struct ast_tcptls_session_instance * ast_tcptls_client_start(struct ast_tcptls_session_instance *tcptls_session)
Attempt to connect and start a tcptls session.
Definition tcptls.c:681
static struct test_options options
#define ast_test_flag(p, flag)
Definition utils.h:63

References ivr_localuser::abort_current_sound, ast_tcptls_session_args::accept_fd, ao2_ref, app_opts, ast_activate_generator(), AST_AF_UNSPEC, ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_chan_log, ast_close_fds_above_n(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, ast_iostream_close(), ast_iostream_from_fd(), AST_LIST_HEAD_INIT_VALUE, AST_LIST_REMOVE_HEAD, ast_log, ast_opt_high_priority, ast_safe_fork(), ast_set_priority(), ast_sockaddr_copy(), ast_sockaddr_port, ast_sockaddr_resolve(), ast_sockaddr_set_port, AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_str_alloca, ast_str_append(), ast_str_reset(), ast_strdupa, ast_strlen_zero(), ast_tcptls_client_create(), ast_tcptls_client_start(), ast_test_flag, ast_verb, buf, ivr_localuser::chan, eivr_comm(), errno, EXTERNALIVR_PORT, ast_flags::flags, gen, ivr_localuser::gen_active, ignore_hangup, LOG_ERROR, MAX_EIVR_APPLICATION_ARGS, noanswer, NULL, options, ivr_localuser::playlist, ast_tcptls_session_args::remote_address, run_dead, and ast_tcptls_session_instance::stream.

◆ ast_eivr_getvariable()

static void ast_eivr_getvariable ( struct ast_channel chan,
char *  data,
char *  outbuf,
int  outbuflen 
)
static

Definition at line 307 of file app_externalivr.c.

308{
309 /* original input data: "G,var1,var2," */
310 /* data passed as "data": "var1,var2" */
311
312 char *inbuf, *variable;
313 const char *value;
314 int j;
315 struct ast_str *newstring = ast_str_alloca(outbuflen);
316
317 outbuf[0] = '\0';
318
319 for (j = 1, inbuf = data; ; j++) {
320 variable = strsep(&inbuf, ",");
321 if (variable == NULL) {
322 int outstrlen = strlen(outbuf);
323 if (outstrlen && outbuf[outstrlen - 1] == ',') {
324 outbuf[outstrlen - 1] = 0;
325 }
326 break;
327 }
328
329 ast_channel_lock(chan);
330 if (!(value = pbx_builtin_getvar_helper(chan, variable))) {
331 value = "";
332 }
333
334 ast_str_append(&newstring, 0, "%s=%s,", variable, value);
335 ast_channel_unlock(chan);
336 ast_copy_string(outbuf, ast_str_buffer(newstring), outbuflen);
337 }
338}
char * strsep(char **str, const char *delims)
#define ast_channel_lock(chan)
Definition channel.h:2982
#define ast_channel_unlock(chan)
Definition channel.h:2983
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
char *attribute_pure ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition strings.h:761
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition strings.h:425
int value
Definition syslog.c:37
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
Definition utils.c:590

References ast_channel_lock, ast_channel_unlock, ast_copy_string(), ast_str_alloca, ast_str_append(), ast_str_buffer(), inbuf(), NULL, pbx_builtin_getvar_helper(), strsep(), and value.

Referenced by eivr_comm().

◆ ast_eivr_senddtmf()

static void ast_eivr_senddtmf ( struct ast_channel chan,
char *  vdata 
)
static

Definition at line 359 of file app_externalivr.c.

360{
361
362 char *data;
363 int dinterval = 0, duration = 0;
365 AST_APP_ARG(digits);
366 AST_APP_ARG(dinterval);
367 AST_APP_ARG(duration);
368 );
369
370 data = ast_strdupa(vdata);
372
373 if (!ast_strlen_zero(args.dinterval)) {
374 ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
375 }
376 if (!ast_strlen_zero(args.duration)) {
377 ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
378 }
379 ast_verb(4, "Sending DTMF: %s %d %d\n", args.digits, dinterval <= 0 ? 250 : dinterval, duration);
380 ast_dtmf_stream(chan, NULL, args.digits, dinterval <= 0 ? 250 : dinterval, duration);
381}
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.
Definition main/app.c:3273
@ TIMELEN_MILLISECONDS
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.
Definition main/app.c:1127
static struct @519 args

References args, AST_APP_ARG, ast_app_parse_timelen(), AST_DECLARE_APP_ARGS, ast_dtmf_stream(), AST_STANDARD_APP_ARGS, ast_strdupa, ast_strlen_zero(), ast_verb, NULL, and TIMELEN_MILLISECONDS.

Referenced by eivr_comm().

◆ ast_eivr_setvariable()

static void ast_eivr_setvariable ( struct ast_channel chan,
char *  data 
)
static

Definition at line 340 of file app_externalivr.c.

341{
342 char *value;
343
344 char *inbuf = ast_strdupa(data), *variable;
345
346 for (variable = strsep(&inbuf, ","); variable; variable = strsep(&inbuf, ",")) {
347 ast_debug(1, "Setting up a variable: %s\n", variable);
348 /* variable contains "varname=value" */
349 value = strchr(variable, '=');
350 if (!value) {
351 value = "";
352 } else {
353 *value++ = '\0';
354 }
355 pbx_builtin_setvar_helper(chan, variable, value);
356 }
357}
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.

References ast_debug, ast_strdupa, inbuf(), pbx_builtin_setvar_helper(), strsep(), and value.

Referenced by eivr_comm().

◆ AST_MODULE_INFO_STANDARD_EXTENDED()

AST_MODULE_INFO_STANDARD_EXTENDED ( ASTERISK_GPL_KEY  ,
"External IVR Interface Application"   
)

◆ eivr_comm()

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

Definition at line 630 of file app_externalivr.c.

635{
636 char input[1024];
637 struct playlist_entry *entry;
638 struct ast_frame *f;
639 int ms;
640 int exception;
641 int ready_fd;
642 int waitfds[2];
643 int r;
644 struct ast_channel *rchan;
645 int res = -1;
646 int hangup_info_sent = 0;
647
648 waitfds[0] = ast_iostream_get_fd(eivr_commands);
649 waitfds[1] = eivr_errors ? ast_iostream_get_fd(eivr_errors) : -1;
650
651 while (1) {
653 ast_chan_log(LOG_ERROR, chan, "Is a zombie\n");
654 break;
655 }
656 if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) {
658 ast_verb(3, "Got check_hangup, but ignore_hangup set so sending 'I' command\n");
659 send_eivr_event(eivr_events, 'I', "HANGUP", chan);
660 hangup_info_sent = 1;
661 } else {
662 ast_verb(3, "Got check_hangup\n");
663 send_eivr_event(eivr_events, 'H', NULL, chan);
664 break;
665 }
666 }
667
668 ready_fd = 0;
669 ms = 100;
670 errno = 0;
671 exception = 0;
672
673 rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors) ? 2 : 1, &exception, &ready_fd, &ms);
674
677 while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
678 send_eivr_event(eivr_events, 'F', entry->filename, chan);
679 ast_free(entry);
680 }
682 }
683
684 if (ast_channel_state(chan) == AST_STATE_UP && !(ast_check_hangup(chan)) && rchan) {
685 /* the channel has something */
686 f = ast_read(chan);
687 if (!f) {
688 ast_verb(3, "Returned no frame\n");
689 send_eivr_event(eivr_events, 'H', NULL, chan);
690 break;
691 }
692 if (f->frametype == AST_FRAME_DTMF) {
693 send_eivr_event(eivr_events, f->subclass.integer, NULL, chan);
694 if (u->option_autoclear) {
696 if (!u->abort_current_sound && !u->playing_silence) {
697 /* send interrupted file as T data */
698 if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
699 send_eivr_event(eivr_events, 'T', entry->filename, chan);
700 ast_free(entry);
701 }
702 }
703 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
704 send_eivr_event(eivr_events, 'D', entry->filename, chan);
705 ast_free(entry);
706 }
707 if (!u->playing_silence)
708 u->abort_current_sound = 1;
710 }
711 } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) {
712 ast_verb(3, "Got AST_CONTROL_HANGUP\n");
713 send_eivr_event(eivr_events, 'H', NULL, chan);
714 if (f->data.uint32) {
716 }
717 ast_frfree(f);
718 break;
719 }
720 ast_frfree(f);
721 } else if (ready_fd == waitfds[0]) {
722 if (exception) {
723 ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
724 break;
725 }
726
727 r = ast_iostream_gets(eivr_commands, input, sizeof(input));
728 if (r <= 0) {
729 if (r == 0) {
730 ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
731 break;
732 }
733 continue;
734 }
735
736 ast_strip(input);
737 ast_verb(4, "got command '%s'\n", input);
738
739 if (strlen(input) < 3) {
740 continue;
741 }
742
743 if (input[0] == EIVR_CMD_PARM) {
744 struct ast_str *tmp = (struct ast_str *) args;
745 send_eivr_event(eivr_events, 'P', ast_str_buffer(tmp), chan);
746 } else if (input[0] == EIVR_CMD_DTMF) {
747 ast_verb(4, "Sending DTMF: %s\n", &input[2]);
748 ast_eivr_senddtmf(chan, &input[2]);
749 } else if (input[0] == EIVR_CMD_ANS) {
750 ast_verb(3, "Answering channel if needed and starting generator\n");
751 if (ast_channel_state(chan) != AST_STATE_UP) {
752 if (ast_test_flag(&flags, run_dead)) {
753 ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
754 send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
755 continue;
756 }
757 if (ast_answer(chan)) {
758 ast_chan_log(LOG_WARNING, chan, "Failed to answer channel\n");
759 send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
760 continue;
761 }
762 }
763 if (!(u->gen_active)) {
764 if (ast_activate_generator(chan, &gen, u) < 0) {
765 ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
766 send_eivr_event(eivr_events, 'Z', "GENERATOR_FAILURE", chan);
767 } else {
768 u->gen_active = 1;
769 }
770 }
771 } else if (input[0] == EIVR_CMD_IRPT) {
772 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
773 ast_chan_log(LOG_WARNING, chan, "Queue 'I'nterrupt called on unanswered channel\n");
774 send_eivr_event(eivr_events, 'Z', NULL, chan);
775 continue;
776 }
778 if (!u->abort_current_sound && !u->playing_silence) {
779 /* send interrupted file as T data */
780 if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
781 send_eivr_event(eivr_events, 'T', entry->filename, chan);
782 ast_free(entry);
783 }
784 }
785 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
786 send_eivr_event(eivr_events, 'D', entry->filename, chan);
787 ast_free(entry);
788 }
789 if (!u->playing_silence) {
790 u->abort_current_sound = 1;
791 }
793 } else if (input[0] == EIVR_CMD_SQUE) {
794 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
795 ast_chan_log(LOG_WARNING, chan, "Queue re'S'et called on unanswered channel\n");
796 send_eivr_event(eivr_events, 'Z', NULL, chan);
797 continue;
798 }
799 if (!ast_fileexists(&input[2], NULL, ast_channel_language(u->chan))) {
800 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
801 send_eivr_event(eivr_events, 'Z', &input[2], chan);
802 } else {
804 if (!u->abort_current_sound && !u->playing_silence) {
805 /* send interrupted file as T data */
806 if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
807 send_eivr_event(eivr_events, 'T', entry->filename, chan);
808 ast_free(entry);
809 }
810 }
811 while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
812 send_eivr_event(eivr_events, 'D', entry->filename, chan);
813 ast_free(entry);
814 }
815 if (!u->playing_silence) {
816 u->abort_current_sound = 1;
817 }
818 entry = make_entry(&input[2]);
819 if (entry) {
820 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
821 }
823 }
824 } else if (input[0] == EIVR_CMD_APND) {
825 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
826 ast_chan_log(LOG_WARNING, chan, "Queue 'A'ppend called on unanswered channel\n");
827 send_eivr_event(eivr_events, 'Z', NULL, chan);
828 continue;
829 }
830 if (!ast_fileexists(&input[2], NULL, ast_channel_language(u->chan))) {
831 ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
832 send_eivr_event(eivr_events, 'Z', &input[2], chan);
833 } else {
834 entry = make_entry(&input[2]);
835 if (entry) {
837 AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
839 }
840 }
841 } else if (input[0] == EIVR_CMD_GET) {
842 char response[2048];
843 ast_verb(4, "Retrieving Variables from channel: %s\n", &input[2]);
844 ast_eivr_getvariable(chan, &input[2], response, sizeof(response));
845 send_eivr_event(eivr_events, 'G', response, chan);
846 } else if (input[0] == EIVR_CMD_SVAR) {
847 ast_verb(4, "Setting Variables in channel: %s\n", &input[2]);
848 ast_eivr_setvariable(chan, &input[2]);
849 } else if (input[0] == EIVR_CMD_LOG) {
850 ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]);
851 } else if (input[0] == EIVR_CMD_XIT) {
852 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
853 ast_chan_log(LOG_WARNING, chan, "e'X'it command is deprecated, use 'E'xit instead\n");
854 res = 0;
855 break;
856 } else if (input[0] == EIVR_CMD_EXIT) {
857 ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
858 send_eivr_event(eivr_events, 'E', NULL, chan);
859 res = 0;
860 break;
861 } else if (input[0] == EIVR_CMD_HGUP) {
862 ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
863 send_eivr_event(eivr_events, 'H', NULL, chan);
864 break;
865 } else if (input[0] == EIVR_CMD_OPT) {
866 if (ast_channel_state(chan) != AST_STATE_UP || ast_check_hangup(chan)) {
867 ast_chan_log(LOG_WARNING, chan, "Option called on unanswered channel\n");
868 send_eivr_event(eivr_events, 'Z', NULL, chan);
869 continue;
870 }
871 if (!strcasecmp(&input[2], "autoclear"))
872 u->option_autoclear = 1;
873 else if (!strcasecmp(&input[2], "noautoclear"))
874 u->option_autoclear = 0;
875 else
876 ast_chan_log(LOG_WARNING, chan, "Unknown option requested: %s\n", &input[2]);
877 }
878 } else if (ready_fd == waitfds[1]) {
879 if (exception) {
880 ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
881 break;
882 }
883
884 r = ast_iostream_gets(eivr_errors, input, sizeof(input));
885 if (r > 0) {
886 ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", ast_strip(input));
887 } else if (r == 0) {
888 ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
889 break;
890 }
891 } else if ((ready_fd < 0) && ms) {
892 if (errno == 0 || errno == EINTR)
893 continue;
894
895 ast_chan_log(LOG_ERROR, chan, "Wait failed (%s)\n", strerror(errno));
896 break;
897 }
898 }
899
900 return res;
901}
#define EIVR_CMD_EXIT
#define EIVR_CMD_XIT
#define EIVR_CMD_SVAR
#define EIVR_CMD_DTMF
#define EIVR_CMD_OPT
static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
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)
#define EIVR_CMD_ANS
#define EIVR_CMD_GET
static void ast_eivr_setvariable(struct ast_channel *chan, char *data)
#define EIVR_CMD_APND
#define EIVR_CMD_IRPT
#define EIVR_CMD_LOG
#define EIVR_CMD_HGUP
#define EIVR_CMD_PARM
static void ast_eivr_senddtmf(struct ast_channel *chan, char *vdata)
#define EIVR_CMD_SQUE
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.
Definition channel.c:2960
struct ast_flags * ast_channel_flags(struct ast_channel *chan)
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition channel.c:4225
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition channel.c:445
const char * ast_channel_language(const struct ast_channel *chan)
@ AST_FLAG_ZOMBIE
Definition channel.h:1007
void ast_channel_hangupcause_set(struct ast_channel *chan, int value)
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition file.c:1148
#define AST_FRAME_DTMF
#define ast_frfree(fr)
@ AST_FRAME_CONTROL
@ AST_CONTROL_HANGUP
#define LOG_NOTICE
#define LOG_WARNING
ssize_t ast_iostream_gets(struct ast_iostream *stream, char *buffer, size_t size)
Read a LF-terminated string from an iostream.
Definition iostream.c:311
int ast_iostream_get_fd(struct ast_iostream *stream)
Get an iostream's file descriptor.
Definition iostream.c:85
#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_LOCK(head)
Locks a list.
Definition linkedlists.h:40
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition strings.h:223
Main Channel structure associated with a channel.
struct ast_flags 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
struct ivr_localuser::finishlist finishlist
char filename[1]

References ivr_localuser::abort_current_sound, args, ast_activate_generator(), ast_answer(), ast_chan_log, ast_channel_flags(), ast_channel_hangupcause_set(), ast_channel_language(), ast_check_hangup(), AST_CONTROL_HANGUP, ast_eivr_getvariable(), ast_eivr_senddtmf(), ast_eivr_setvariable(), ast_fileexists(), AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_free, ast_frfree, ast_iostream_get_fd(), ast_iostream_gets(), AST_LIST_EMPTY, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_read(), AST_STATE_UP, ast_str_buffer(), ast_strip(), ast_test_flag, ast_verb, ast_waitfor_nandfds(), ivr_localuser::chan, ast_frame::data, EIVR_CMD_ANS, EIVR_CMD_APND, EIVR_CMD_DTMF, EIVR_CMD_EXIT, EIVR_CMD_GET, EIVR_CMD_HGUP, EIVR_CMD_IRPT, EIVR_CMD_LOG, EIVR_CMD_OPT, EIVR_CMD_PARM, EIVR_CMD_SQUE, EIVR_CMD_SVAR, EIVR_CMD_XIT, errno, playlist_entry::filename, ivr_localuser::finishlist, ast_channel::flags, ast_frame::frametype, gen, ivr_localuser::gen_active, ignore_hangup, ast_frame_subclass::integer, LOG_ERROR, LOG_NOTICE, LOG_WARNING, make_entry(), NULL, ivr_localuser::option_autoclear, ivr_localuser::playing_silence, ivr_localuser::playlist, run_dead, send_eivr_event(), ast_frame::subclass, and ast_frame::uint32.

Referenced by app_exec().

◆ gen_alloc()

static void * gen_alloc ( struct ast_channel chan,
void *  params 
)
static

Definition at line 178 of file app_externalivr.c.

179{
180 struct ivr_localuser *u = params;
181 struct gen_state *state;
182
183 if (!(state = ast_calloc(1, sizeof(*state))))
184 return NULL;
185
186 state->u = u;
187
188 return state;
189}
#define ast_calloc(num, len)
A wrapper for calloc()
Definition astmm.h:202
struct ivr_localuser * u

References ast_calloc, NULL, and gen_state::u.

◆ gen_closestream()

static void gen_closestream ( struct gen_state state)
static

Definition at line 191 of file app_externalivr.c.

192{
193 if (!state->stream)
194 return;
195
196 ast_closestream(state->stream);
198 state->stream = NULL;
199}
void ast_channel_stream_set(struct ast_channel *chan, struct ast_filestream *value)
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition file.c:1130

References ast_channel_stream_set(), ast_closestream(), and NULL.

Referenced by gen_nextfile(), gen_readframe(), and gen_release().

◆ gen_generate()

static int gen_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
)
static

Definition at line 276 of file app_externalivr.c.

277{
278 struct gen_state *state = data;
279 struct ast_frame *f = NULL;
280 int res = 0;
281
282 state->sample_queue += samples;
283
284 while (state->sample_queue > 0) {
285 if (!(f = gen_readframe(state)))
286 return -1;
287
288 res = ast_write(chan, f);
289 ast_frfree(f);
290 if (res < 0) {
291 ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
292 return -1;
293 }
294 state->sample_queue -= f->samples;
295 }
296
297 return res;
298}
static struct ast_frame * gen_readframe(struct gen_state *state)
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.
Definition channel.c:5114

References ast_chan_log, ast_frfree, ast_write(), errno, gen_readframe(), LOG_WARNING, NULL, and ast_frame::samples.

◆ gen_nextfile()

static int gen_nextfile ( struct gen_state state)
static

Definition at line 210 of file app_externalivr.c.

211{
212 struct ivr_localuser *u = state->u;
213 char *file_to_stream;
214
215 u->abort_current_sound = 0;
216 u->playing_silence = 0;
218
219 while (!state->stream) {
220 state->current = AST_LIST_FIRST(&u->playlist);
221 if (state->current) {
222 file_to_stream = state->current->filename;
223 } else {
224 file_to_stream = "silence/10";
225 u->playing_silence = 1;
226 }
227
228 if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, ast_channel_language(u->chan), 1))) {
229 ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
233 if (!u->playing_silence) {
234 continue;
235 } else {
236 break;
237 }
238 }
239 }
240
241 return (!state->stream);
242}
static void gen_closestream(struct gen_state *state)
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.
Definition file.c:861
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.

References ivr_localuser::abort_current_sound, ast_chan_log, ast_channel_language(), AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_openstream_full(), ivr_localuser::chan, errno, gen_closestream(), LOG_WARNING, ivr_localuser::playing_silence, and ivr_localuser::playlist.

Referenced by gen_readframe().

◆ gen_readframe()

static struct ast_frame * gen_readframe ( struct gen_state state)
static

Definition at line 244 of file app_externalivr.c.

245{
246 struct ast_frame *f = NULL;
247 struct ivr_localuser *u = state->u;
248
249 if (u->abort_current_sound ||
255 }
256
257 if (!(state->stream && (f = ast_readframe(state->stream)))) {
258 if (state->current) {
259 /* remove finished file from playlist */
263 /* add finished file to finishlist */
265 AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
267 state->current = NULL;
268 }
269 if (!gen_nextfile(state))
270 f = ast_readframe(state->stream);
271 }
272
273 return f;
274}
static int gen_nextfile(struct gen_state *state)
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
Definition file.c:955

References ivr_localuser::abort_current_sound, AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_readframe(), ivr_localuser::finishlist, gen_closestream(), gen_nextfile(), NULL, ivr_localuser::playing_silence, and ivr_localuser::playlist.

Referenced by gen_generate().

◆ gen_release()

static void gen_release ( struct ast_channel chan,
void *  data 
)
static

Definition at line 201 of file app_externalivr.c.

202{
203 struct gen_state *state = data;
204
206 ast_free(data);
207}

References ast_free, and gen_closestream().

◆ load_module()

static int load_module ( void  )
static

Definition at line 908 of file app_externalivr.c.

909{
911}
static const char app_exec[]
Definition app_exec.c:138
static const char app[]
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition module.h:640

References app, app_exec, and ast_register_application_xml.

◆ make_entry()

static struct playlist_entry * make_entry ( const char *  filename)
static

Definition at line 383 of file app_externalivr.c.

384{
385 struct playlist_entry *entry;
386
387 if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10))) /* XXX why 10 ? */
388 return NULL;
389
390 strcpy(entry->filename, filename);
391
392 return entry;
393}

References ast_calloc, playlist_entry::filename, and NULL.

Referenced by eivr_comm().

◆ send_eivr_event()

static void send_eivr_event ( struct ast_iostream stream,
const char  event,
const char *  data,
const struct ast_channel chan 
)
static

Definition at line 161 of file app_externalivr.c.

163{
164 struct ast_str *tmp = ast_str_create(12);
165
166 ast_str_append(&tmp, 0, "%c,%10d", event, (int)time(NULL));
167 if (data) {
168 ast_str_append(&tmp, 0, ",%s", data);
169 }
170 ast_str_append(&tmp, 0, "\n");
171 ast_iostream_write(stream, ast_str_buffer(tmp), strlen(ast_str_buffer(tmp)));
172 ast_str_truncate(tmp, -1);
173
174 ast_debug(1, "sent '%s'", ast_str_buffer(tmp));
175 ast_free(tmp);
176}
ssize_t ast_iostream_write(struct ast_iostream *stream, const void *buffer, size_t count)
Write data to an iostream.
Definition iostream.c:385
char * ast_str_truncate(struct ast_str *buf, ssize_t len)
Truncates the enclosed string to the given length.
Definition strings.h:786
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
Definition strings.h:659

References ast_debug, ast_free, ast_iostream_write(), ast_str_append(), ast_str_buffer(), ast_str_create, ast_str_truncate(), and NULL.

Referenced by eivr_comm().

◆ unload_module()

static int unload_module ( void  )
static

Definition at line 903 of file app_externalivr.c.

904{
906}
int ast_unregister_application(const char *app)
Unregister an application.
Definition pbx_app.c:392

References app, and ast_unregister_application().

Variable Documentation

◆ app

const char app[] = "ExternalIVR"
static

Definition at line 98 of file app_externalivr.c.

Referenced by load_module(), and unload_module().

◆ app_opts

const struct ast_app_option app_opts[128] = { [ 'n' ] = { .flag = noanswer }, [ 'i' ] = { .flag = ignore_hangup }, [ 'd' ] = { .flag = run_dead }, }
static

Definition at line 130 of file app_externalivr.c.

Referenced by app_exec().

◆ gen

struct ast_generator gen
static

Definition at line 300 of file app_externalivr.c.

301{
302 .alloc = gen_alloc,
303 .release = gen_release,
304 .generate = gen_generate,
305};
static void gen_release(struct ast_channel *chan, void *data)
static void * gen_alloc(struct ast_channel *chan, void *params)
static int gen_generate(struct ast_channel *chan, void *data, int len, int samples)

Referenced by app_exec(), ast_activate_generator(), eivr_comm(), find_body_generator_type_subtype(), and find_body_generator_type_subtype_nolock().