Wed Jan 8 2020 09:49:53

Asterisk developer's documentation


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"

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, channel->name , ## __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_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** */
 

Enumerations

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

Functions

static void __reg_module (void)
 
static void __unreg_module (void)
 
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)
 
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)
 
int eivr_connect_socket (struct ast_channel *chan, const char *host, int port)
 
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 (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_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
 
static const char app [] = "ExternalIVR"
 
static struct ast_app_option app_opts [128] = { [ 'n' ] = { .flag = noanswer }, [ 'i' ] = { .flag = ignore_hangup }, [ 'd' ] = { .flag = run_dead }, }
 
static struct ast_module_infoast_module_info = &__mod_info
 
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

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

Definition at line 100 of file app_externalivr.c.

Referenced by app_exec(), eivr_comm(), gen_generate(), and gen_nextfile().

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

Definition at line 112 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 103 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 104 of file app_externalivr.c.

Referenced by eivr_comm().

#define EIVR_CMD_EXIT   'E' /* exit */

Definition at line 105 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 106 of file app_externalivr.c.

Referenced by eivr_comm().

#define EIVR_CMD_HGUP   'H' /* hangup */

Definition at line 107 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 108 of file app_externalivr.c.

Referenced by eivr_comm().

#define EIVR_CMD_OPT   'O' /* option */

Definition at line 109 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 110 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 111 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 113 of file app_externalivr.c.

Referenced by eivr_comm().

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

Definition at line 114 of file app_externalivr.c.

Referenced by eivr_comm().

Enumeration Type Documentation

Enumerator
noanswer 
ignore_hangup 
run_dead 

Definition at line 116 of file app_externalivr.c.

116  {
117  noanswer = (1 << 0),
118  ignore_hangup = (1 << 1),
119  run_dead = (1 << 2),
120 };

Function Documentation

static void __reg_module ( void  )
static

Definition at line 891 of file app_externalivr.c.

static void __unreg_module ( void  )
static

Definition at line 891 of file app_externalivr.c.

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

Definition at line 389 of file app_externalivr.c.

References ast_channel::_state, ivr_localuser::abort_current_sound, ast_tcptls_session_args::accept_fd, ao2_ref, app_opts, ast_activate_generator(), ast_answer(), AST_APP_ARG, ast_app_parse_options(), ast_chan_log, ast_close_fds_above_n(), ast_copy_string(), ast_deactivate_generator(), ast_debug, AST_DECLARE_APP_ARGS, ast_free, ast_gethostbyname(), AST_LIST_HEAD_INIT_VALUE, AST_LIST_REMOVE_HEAD, ast_log(), ast_opt_high_priority, ast_safe_fork(), ast_set_priority(), ast_sockaddr_from_sin, 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, ivr_localuser::chan, eivr_comm(), errno, ast_tcptls_session_instance::fd, ivr_localuser::gen_active, hostname, ast_hostent::hp, ignore_hangup, LOG_ERROR, noanswer, ivr_localuser::playlist, ast_tcptls_session_args::remote_address, and run_dead.

Referenced by load_module().

390 {
391  struct ast_flags flags = { 0, };
392  char *opts[0];
393  struct playlist_entry *entry;
394  int child_stdin[2] = { -1, -1 };
395  int child_stdout[2] = { -1, -1 };
396  int child_stderr[2] = { -1, -1 };
397  int res = -1;
398  int pid;
399 
400  char hostname[1024];
401  char *port_str = NULL;
402  int port = 0;
403  struct ast_tcptls_session_instance *ser = NULL;
404 
405  struct ivr_localuser foo = {
407  .finishlist = AST_LIST_HEAD_INIT_VALUE,
408  .gen_active = 0,
409  };
410  struct ivr_localuser *u = &foo;
411 
412  char *buf;
413  int j;
414  char *s, **app_args, *e;
415  struct ast_str *comma_delim_args = ast_str_alloca(100);
416 
417  AST_DECLARE_APP_ARGS(eivr_args,
418  AST_APP_ARG(application);
419  AST_APP_ARG(options);
420  );
421  AST_DECLARE_APP_ARGS(application_args,
422  AST_APP_ARG(cmd)[32];
423  );
424 
425  u->abort_current_sound = 0;
426  u->chan = chan;
427 
428  if (ast_strlen_zero(data)) {
429  ast_log(LOG_ERROR, "ExternalIVR requires a command to execute\n");
430  goto exit;
431  }
432 
433  buf = ast_strdupa(data);
434  AST_STANDARD_APP_ARGS(eivr_args, buf);
435 
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);
438 
439  /* Parse out any application arguments */
440  if ((s = strchr(eivr_args.application, '('))) {
441  s[0] = ',';
442  if ((e = strrchr(s, ')'))) {
443  *e = '\0';
444  } else {
445  ast_log(LOG_ERROR, "Parse error, missing closing parenthesis\n");
446  goto exit;
447  }
448  }
449 
450  AST_STANDARD_APP_ARGS(application_args, eivr_args.application);
451  app_args = application_args.argv;
452 
453  /* Put the application + the arguments in a , delimited list */
454  ast_str_reset(comma_delim_args);
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]);
457  }
458 
459  /* Get rid of any extraneous arguments */
460  if (eivr_args.options && (s = strchr(eivr_args.options, ','))) {
461  *s = '\0';
462  }
463 
464  /* Parse the ExternalIVR() arguments */
465  ast_verb(4, "Parsing options from: [%s]\n", eivr_args.options);
466  ast_app_parse_options(app_opts, &flags, opts, eivr_args.options);
467  if (ast_test_flag(&flags, noanswer)) {
468  ast_verb(4, "noanswer is set\n");
469  }
470  if (ast_test_flag(&flags, ignore_hangup)) {
471  ast_verb(4, "ignore_hangup is set\n");
472  }
473  if (ast_test_flag(&flags, run_dead)) {
474  ast_verb(4, "run_dead is set\n");
475  }
476 
477  if (!(ast_test_flag(&flags, noanswer))) {
478  ast_verb(3, "Answering channel and starting generator\n");
479  if (chan->_state != AST_STATE_UP) {
480  if (ast_test_flag(&flags, run_dead)) {
481  ast_chan_log(LOG_ERROR, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
482  goto exit;
483  }
484  ast_answer(chan);
485  }
486  if (ast_activate_generator(chan, &gen, u) < 0) {
487  ast_chan_log(LOG_ERROR, chan, "Failed to activate generator\n");
488  goto exit;
489  } else {
490  u->gen_active = 1;
491  }
492  }
493 
494  if (!strncmp(app_args[0], "ivr://", 6)) {
495  struct ast_tcptls_session_args ivr_desc = {
496  .accept_fd = -1,
497  .name = "IVR",
498  };
499  struct ast_hostent hp;
500  struct sockaddr_in remote_address_tmp;
501 
502  /*communicate through socket to server*/
503  ast_debug(1, "Parsing hostname:port for socket connect from \"%s\"\n", app_args[0]);
504  ast_copy_string(hostname, app_args[0] + 6, sizeof(hostname));
505  if ((port_str = strchr(hostname, ':')) != NULL) {
506  port_str[0] = 0;
507  port_str += 1;
508  port = atoi(port_str);
509  }
510  if (!port) {
511  port = 2949; /* default port, if one is not provided */
512  }
513 
514  ast_gethostbyname(hostname, &hp);
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);
518  ast_sockaddr_from_sin(&ivr_desc.remote_address, &remote_address_tmp);
519  if (!(ser = ast_tcptls_client_create(&ivr_desc)) || !(ser = ast_tcptls_client_start(ser))) {
520  goto exit;
521  }
522  res = eivr_comm(chan, u, &ser->fd, &ser->fd, NULL, comma_delim_args, flags);
523 
524  } else {
525  if (pipe(child_stdin)) {
526  ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child input: %s\n", strerror(errno));
527  goto exit;
528  }
529  if (pipe(child_stdout)) {
530  ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child output: %s\n", strerror(errno));
531  goto exit;
532  }
533  if (pipe(child_stderr)) {
534  ast_chan_log(LOG_ERROR, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
535  goto exit;
536  }
537 
538  pid = ast_safe_fork(0);
539  if (pid < 0) {
540  ast_log(LOG_ERROR, "Failed to fork(): %s\n", strerror(errno));
541  goto exit;
542  }
543 
544  if (!pid) {
545  /* child process */
547  ast_set_priority(0);
548 
549  dup2(child_stdin[0], STDIN_FILENO);
550  dup2(child_stdout[1], STDOUT_FILENO);
551  dup2(child_stderr[1], STDERR_FILENO);
552  ast_close_fds_above_n(STDERR_FILENO);
553  execv(app_args[0], app_args);
554  fprintf(stderr, "Failed to execute '%s': %s\n", app_args[0], strerror(errno));
555  _exit(1);
556  } else {
557  /* parent process */
558  close(child_stdin[0]);
559  child_stdin[0] = -1;
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);
565  }
566  }
567 
568  exit:
569  if (u->gen_active) {
571  }
572  if (child_stdin[0] > -1) {
573  close(child_stdin[0]);
574  }
575  if (child_stdin[1] > -1) {
576  close(child_stdin[1]);
577  }
578  if (child_stdout[0] > -1) {
579  close(child_stdout[0]);
580  }
581  if (child_stdout[1] > -1) {
582  close(child_stdout[1]);
583  }
584  if (child_stderr[0] > -1) {
585  close(child_stderr[0]);
586  }
587  if (child_stderr[1] > -1) {
588  close(child_stderr[1]);
589  }
590  if (ser) {
591  ao2_ref(ser, -1);
592  }
593  while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
594  ast_free(entry);
595  }
596  return res;
597 }
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: app.c:2242
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)
Definition: utils.h:63
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:3148
#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.
Definition: app.c:2101
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
unsigned int flags
Definition: utils.h:201
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:900
arguments for the accepting thread
Definition: tcptls.h:123
#define ast_str_alloca(init_len)
Definition: strings.h:608
#define ast_verb(level,...)
Definition: logger.h:243
static struct ast_app_option app_opts[128]
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ast_sockaddr_from_sin(addr, sin)
Converts a struct sockaddr_in to a struct ast_sockaddr.
Definition: netsock2.h:642
static struct ast_generator gen
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
struct ast_sockaddr remote_address
Definition: tcptls.h:126
#define ao2_ref(o, delta)
Definition: astobj2.h:472
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
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:1650
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
#define LOG_ERROR
Definition: logger.h:155
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
enum ast_channel_state _state
Definition: channel.h:839
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...
Definition: logger.c:1207
int errno
#define ast_free(a)
Definition: astmm.h:97
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Definition: app.c:2237
Structure used to handle boolean flags.
Definition: utils.h:200
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:436
void ast_deactivate_generator(struct ast_channel *chan)
Definition: channel.c:3107
struct hostent * ast_gethostbyname(const char *host, struct ast_hostent *hp)
Thread-safe gethostbyname function to use in Asterisk.
Definition: utils.c:195
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
struct ast_tcptls_session_instance * ast_tcptls_client_create(struct ast_tcptls_session_args *desc)
Definition: tcptls.c:902
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
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&#39;s ref count is decremented...
Definition: tcptls.c:865
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
#define AST_LIST_HEAD_INIT_VALUE
Defines initial values for a declaration of AST_LIST_HEAD.
Definition: linkedlists.h:233
static struct hostent * hp
Definition: chan_skinny.c:1048
#define ast_opt_high_priority
Definition: options.h:108
static char hostname[MAXHOSTNAMELEN]
Definition: logger.c:91
struct ast_channel * chan
static void ast_eivr_getvariable ( struct ast_channel chan,
char *  data,
char *  outbuf,
int  outbuflen 
)
static

Definition at line 301 of file app_externalivr.c.

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

Referenced by eivr_comm().

302 {
303  /* original input data: "G,var1,var2," */
304  /* data passed as "data": "var1,var2" */
305 
306  char *inbuf, *variable;
307  const char *value;
308  int j;
309  struct ast_str *newstring = ast_str_alloca(outbuflen);
310 
311  outbuf[0] = '\0';
312 
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;
319  }
320  break;
321  }
322 
323  ast_channel_lock(chan);
324  if (!(value = pbx_builtin_getvar_helper(chan, variable))) {
325  value = "";
326  }
327 
328  ast_str_append(&newstring, 0, "%s=%s,", variable, value);
329  ast_channel_unlock(chan);
330  ast_copy_string(outbuf, ast_str_buffer(newstring), outbuflen);
331  }
332 }
#define ast_channel_lock(chan)
Definition: channel.h:2466
char * strsep(char **str, const char *delims)
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
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:900
#define ast_str_alloca(init_len)
Definition: strings.h:608
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
int value
Definition: syslog.c:39
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
Definition: pbx.c:10475
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
#define ast_channel_unlock(chan)
Definition: channel.h:2467
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
Definition: strings.h:223
static void ast_eivr_senddtmf ( struct ast_channel chan,
char *  vdata 
)
static

Definition at line 353 of file app_externalivr.c.

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, and TIMELEN_MILLISECONDS.

Referenced by eivr_comm().

354 {
355 
356  char *data;
357  int dinterval = 0, duration = 0;
359  AST_APP_ARG(digits);
360  AST_APP_ARG(dinterval);
361  AST_APP_ARG(duration);
362  );
363 
364  data = ast_strdupa(vdata);
366 
367  if (!ast_strlen_zero(args.dinterval)) {
368  ast_app_parse_timelen(args.dinterval, &dinterval, TIMELEN_MILLISECONDS);
369  }
370  if (!ast_strlen_zero(args.duration)) {
371  ast_app_parse_timelen(args.duration, &duration, TIMELEN_MILLISECONDS);
372  }
373  ast_verb(4, "Sending DTMF: %s %d %d\n", args.digits, dinterval <= 0 ? 250 : dinterval, duration);
374  ast_dtmf_stream(chan, NULL, args.digits, dinterval <= 0 ? 250 : dinterval, duration);
375 }
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: app.c:2311
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application&#39;s arguments.
Definition: app.h:572
#define ast_verb(level,...)
Definition: logger.h:243
static force_inline int attribute_pure ast_strlen_zero(const char *s)
Definition: strings.h:63
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
static struct @350 args
#define AST_APP_ARG(name)
Define an application argument.
Definition: app.h:555
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the &#39;standard&#39; argument separation process for an application.
Definition: app.h:604
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.
Definition: app.c:501
static void ast_eivr_setvariable ( struct ast_channel chan,
char *  data 
)
static

Definition at line 334 of file app_externalivr.c.

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

Referenced by eivr_comm().

335 {
336  char *value;
337 
338  char *inbuf = ast_strdupa(data), *variable;
339 
340  for (variable = strsep(&inbuf, ","); variable; variable = strsep(&inbuf, ",")) {
341  ast_debug(1, "Setting up a variable: %s\n", variable);
342  /* variable contains "varname=value" */
343  value = strchr(variable, '=');
344  if (!value) {
345  value = "";
346  } else {
347  *value++ = '\0';
348  }
349  pbx_builtin_setvar_helper(chan, variable, value);
350  }
351 }
char * strsep(char **str, const char *delims)
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
int value
Definition: syslog.c:39
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
#define ast_strdupa(s)
duplicate a string in memory from the stack
Definition: utils.h:663
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...
Definition: pbx.c:10546
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 
)
static

Definition at line 599 of file app_externalivr.c.

References ast_channel::_state, ivr_localuser::abort_current_sound, ast_activate_generator(), ast_answer(), ast_chan_log, 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_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_LOG, EIVR_CMD_OPT, EIVR_CMD_PARM, EIVR_CMD_SQUE, EIVR_CMD_SVAR, EIVR_CMD_XIT, errno, f, playlist_entry::filename, ivr_localuser::finishlist, ast_frame::frametype, ivr_localuser::gen_active, ast_channel::hangupcause, ignore_hangup, input(), ast_frame_subclass::integer, ast_channel::language, LOG_ERROR, LOG_NOTICE, LOG_WARNING, make_entry(), 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().

602 {
603  struct playlist_entry *entry;
604  struct ast_frame *f;
605  int ms;
606  int exception;
607  int ready_fd;
608  int waitfds[2] = { *eivr_commands_fd, (eivr_errors_fd) ? *eivr_errors_fd : -1 };
609  struct ast_channel *rchan;
610  int res = -1;
611  int test_available_fd = -1;
612  int hangup_info_sent = 0;
613 
614  FILE *eivr_commands = NULL;
615  FILE *eivr_errors = NULL;
616  FILE *eivr_events = NULL;
617 
618  if (!(eivr_events = fdopen(*eivr_events_fd, "w"))) {
619  ast_chan_log(LOG_ERROR, chan, "Could not open stream to send events\n");
620  goto exit;
621  }
622  if (!(eivr_commands = fdopen(*eivr_commands_fd, "r"))) {
623  ast_chan_log(LOG_ERROR, chan, "Could not open stream to receive commands\n");
624  goto exit;
625  }
626  if (eivr_errors_fd) { /* if opening a socket connection, error stream will not be used */
627  if (!(eivr_errors = fdopen(*eivr_errors_fd, "r"))) {
628  ast_chan_log(LOG_ERROR, chan, "Could not open stream to receive errors\n");
629  goto exit;
630  }
631  }
632 
633  test_available_fd = open("/dev/null", O_RDONLY);
634 
635  setvbuf(eivr_events, NULL, _IONBF, 0);
636  setvbuf(eivr_commands, NULL, _IONBF, 0);
637  if (eivr_errors) {
638  setvbuf(eivr_errors, NULL, _IONBF, 0);
639  }
640 
641  while (1) {
642  if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
643  ast_chan_log(LOG_ERROR, chan, "Is a zombie\n");
644  break;
645  }
646  if (!hangup_info_sent && !(ast_test_flag(&flags, run_dead)) && ast_check_hangup(chan)) {
647  if (ast_test_flag(&flags, ignore_hangup)) {
648  ast_verb(3, "Got check_hangup, but ignore_hangup set so sending 'I' command\n");
649  send_eivr_event(eivr_events, 'I', "HANGUP", chan);
650  hangup_info_sent = 1;
651  } else {
652  ast_verb(3, "Got check_hangup\n");
653  send_eivr_event(eivr_events, 'H', NULL, chan);
654  break;
655  }
656  }
657 
658  ready_fd = 0;
659  ms = 100;
660  errno = 0;
661  exception = 0;
662 
663  rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd) ? 2 : 1, &exception, &ready_fd, &ms);
664 
665  if (chan->_state == AST_STATE_UP && !AST_LIST_EMPTY(&u->finishlist)) {
667  while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
668  send_eivr_event(eivr_events, 'F', entry->filename, chan);
669  ast_free(entry);
670  }
672  }
673 
674  if (chan->_state == AST_STATE_UP && !(ast_check_hangup(chan)) && rchan) {
675  /* the channel has something */
676  f = ast_read(chan);
677  if (!f) {
678  ast_verb(3, "Returned no frame\n");
679  send_eivr_event(eivr_events, 'H', NULL, chan);
680  break;
681  }
682  if (f->frametype == AST_FRAME_DTMF) {
683  send_eivr_event(eivr_events, f->subclass.integer, NULL, chan);
684  if (u->option_autoclear) {
685  AST_LIST_LOCK(&u->playlist);
686  if (!u->abort_current_sound && !u->playing_silence) {
687  /* send interrupted file as T data */
688  if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
689  send_eivr_event(eivr_events, 'T', entry->filename, chan);
690  ast_free(entry);
691  }
692  }
693  while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
694  send_eivr_event(eivr_events, 'D', entry->filename, chan);
695  ast_free(entry);
696  }
697  if (!u->playing_silence)
698  u->abort_current_sound = 1;
700  }
701  } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass.integer == AST_CONTROL_HANGUP)) {
702  ast_verb(3, "Got AST_CONTROL_HANGUP\n");
703  send_eivr_event(eivr_events, 'H', NULL, chan);
704  if (f->data.uint32) {
705  chan->hangupcause = f->data.uint32;
706  }
707  ast_frfree(f);
708  break;
709  }
710  ast_frfree(f);
711  } else if (ready_fd == *eivr_commands_fd) {
712  char input[1024];
713 
714  if (exception || (dup2(*eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) {
715  ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
716  break;
717  }
718 
719  if (!fgets(input, sizeof(input), eivr_commands)) {
720  continue;
721  }
722 
723  ast_strip(input);
724  ast_verb(4, "got command '%s'\n", input);
725 
726  if (strlen(input) < 3) {
727  continue;
728  }
729 
730  if (input[0] == EIVR_CMD_PARM) {
731  struct ast_str *tmp = (struct ast_str *) args;
732  send_eivr_event(eivr_events, 'P', ast_str_buffer(tmp), chan);
733  } else if (input[0] == EIVR_CMD_DTMF) {
734  ast_verb(4, "Sending DTMF: %s\n", &input[2]);
735  ast_eivr_senddtmf(chan, &input[2]);
736  } else if (input[0] == EIVR_CMD_ANS) {
737  ast_verb(3, "Answering channel if needed and starting generator\n");
738  if (chan->_state != AST_STATE_UP) {
739  if (ast_test_flag(&flags, run_dead)) {
740  ast_chan_log(LOG_WARNING, chan, "Running ExternalIVR with 'd'ead flag on non-hungup channel isn't supported\n");
741  send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
742  continue;
743  }
744  if (ast_answer(chan)) {
745  ast_chan_log(LOG_WARNING, chan, "Failed to answer channel\n");
746  send_eivr_event(eivr_events, 'Z', "ANSWER_FAILURE", chan);
747  continue;
748  }
749  }
750  if (!(u->gen_active)) {
751  if (ast_activate_generator(chan, &gen, u) < 0) {
752  ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
753  send_eivr_event(eivr_events, 'Z', "GENERATOR_FAILURE", chan);
754  } else {
755  u->gen_active = 1;
756  }
757  }
758  } else if (input[0] == EIVR_CMD_SQUE) {
759  if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
760  ast_chan_log(LOG_WARNING, chan, "Queue re'S'et called on unanswered channel\n");
761  send_eivr_event(eivr_events, 'Z', NULL, chan);
762  continue;
763  }
764  if (!ast_fileexists(&input[2], NULL, u->chan->language)) {
765  ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
766  send_eivr_event(eivr_events, 'Z', &input[2], chan);
767  } else {
768  AST_LIST_LOCK(&u->playlist);
769  if (!u->abort_current_sound && !u->playing_silence) {
770  /* send interrupted file as T data */
771  if ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
772  send_eivr_event(eivr_events, 'T', entry->filename, chan);
773  ast_free(entry);
774  }
775  }
776  while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
777  send_eivr_event(eivr_events, 'D', entry->filename, chan);
778  ast_free(entry);
779  }
780  if (!u->playing_silence) {
781  u->abort_current_sound = 1;
782  }
783  entry = make_entry(&input[2]);
784  if (entry) {
785  AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
786  }
788  }
789  } else if (input[0] == EIVR_CMD_APND) {
790  if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
791  ast_chan_log(LOG_WARNING, chan, "Queue 'A'ppend called on unanswered channel\n");
792  send_eivr_event(eivr_events, 'Z', NULL, chan);
793  continue;
794  }
795  if (!ast_fileexists(&input[2], NULL, u->chan->language)) {
796  ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
797  send_eivr_event(eivr_events, 'Z', &input[2], chan);
798  } else {
799  entry = make_entry(&input[2]);
800  if (entry) {
801  AST_LIST_LOCK(&u->playlist);
802  AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
804  }
805  }
806  } else if (input[0] == EIVR_CMD_GET) {
807  char response[2048];
808  ast_verb(4, "Retriving Variables from channel: %s\n", &input[2]);
809  ast_eivr_getvariable(chan, &input[2], response, sizeof(response));
810  send_eivr_event(eivr_events, 'G', response, chan);
811  } else if (input[0] == EIVR_CMD_SVAR) {
812  ast_verb(4, "Setting Variables in channel: %s\n", &input[2]);
813  ast_eivr_setvariable(chan, &input[2]);
814  } else if (input[0] == EIVR_CMD_LOG) {
815  ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]);
816  } else if (input[0] == EIVR_CMD_XIT) {
817  ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
818  ast_chan_log(LOG_WARNING, chan, "e'X'it command is depricated, use 'E'xit instead\n");
819  res = 0;
820  break;
821  } else if (input[0] == EIVR_CMD_EXIT) {
822  ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
823  send_eivr_event(eivr_events, 'E', NULL, chan);
824  res = 0;
825  break;
826  } else if (input[0] == EIVR_CMD_HGUP) {
827  ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
828  send_eivr_event(eivr_events, 'H', NULL, chan);
829  break;
830  } else if (input[0] == EIVR_CMD_OPT) {
831  if (chan->_state != AST_STATE_UP || ast_check_hangup(chan)) {
832  ast_chan_log(LOG_WARNING, chan, "Option called on unanswered channel\n");
833  send_eivr_event(eivr_events, 'Z', NULL, chan);
834  continue;
835  }
836  if (!strcasecmp(&input[2], "autoclear"))
837  u->option_autoclear = 1;
838  else if (!strcasecmp(&input[2], "noautoclear"))
839  u->option_autoclear = 0;
840  else
841  ast_chan_log(LOG_WARNING, chan, "Unknown option requested: %s\n", &input[2]);
842  }
843  } else if (eivr_errors_fd && (ready_fd == *eivr_errors_fd)) {
844  char input[1024];
845 
846  if (exception || feof(eivr_errors)) {
847  ast_chan_log(LOG_ERROR, chan, "Child process went away\n");
848  break;
849  }
850  if (fgets(input, sizeof(input), eivr_errors)) {
851  ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", ast_strip(input));
852  }
853  } else if ((ready_fd < 0) && ms) {
854  if (errno == 0 || errno == EINTR)
855  continue;
856 
857  ast_chan_log(LOG_ERROR, chan, "Wait failed (%s)\n", strerror(errno));
858  break;
859  }
860  }
861 
862  exit:
863  if (test_available_fd > -1) {
864  close(test_available_fd);
865  }
866  if (eivr_events) {
867  fclose(eivr_events);
868  *eivr_events_fd = -1;
869  }
870  if (eivr_commands) {
871  fclose(eivr_commands);
872  *eivr_commands_fd = -1;
873  }
874  if (eivr_errors) {
875  fclose(eivr_errors);
876  *eivr_errors_fd = -1;
877  }
878  return res;
879 }
union ast_frame_subclass subclass
Definition: frame.h:146
Main Channel structure associated with a channel.
Definition: channel.h:742
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
static void ast_eivr_getvariable(struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
#define EIVR_CMD_XIT
struct ivr_localuser::playlist playlist
#define ast_test_flag(p, flag)
Definition: utils.h:63
int ast_activate_generator(struct ast_channel *chan, struct ast_generator *gen, void *params)
Definition: channel.c:3148
#define LOG_WARNING
Definition: logger.h:144
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
#define ast_chan_log(level, channel, format,...)
#define AST_FRAME_DTMF
Definition: frame.h:128
#define EIVR_CMD_SVAR
#define EIVR_CMD_PARM
struct ast_frame * ast_read(struct ast_channel *chan)
Reads a frame.
Definition: channel.c:4383
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
Definition: linkedlists.h:449
static int input(yyscan_t yyscanner)
Definition: ast_expr2f.c:1575
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.
Definition: channel.c:3188
#define ast_verb(level,...)
Definition: logger.h:243
static struct ast_generator gen
char * ast_strip(char *s)
Strip leading/trailing whitespace from a string.
Definition: strings.h:155
static void ast_eivr_senddtmf(struct ast_channel *chan, char *vdata)
#define EIVR_CMD_APND
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
Definition: channel.c:806
#define EIVR_CMD_EXIT
#define LOG_ERROR
Definition: logger.h:155
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
#define EIVR_CMD_OPT
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
#define EIVR_CMD_DTMF
#define EIVR_CMD_ANS
enum ast_channel_state _state
Definition: channel.h:839
#define LOG_NOTICE
Definition: logger.h:133
int errno
#define ast_free(a)
Definition: astmm.h:97
static struct ast_format f[]
Definition: format_g726.c:181
char filename[1]
#define EIVR_CMD_SQUE
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
Definition: file.c:919
int ast_answer(struct ast_channel *chan)
Answer a channel.
Definition: channel.c:3086
Data structure associated with a single frame of data.
Definition: frame.h:142
int hangupcause
Definition: channel.h:849
struct ivr_localuser::finishlist finishlist
#define EIVR_CMD_LOG
uint32_t uint32
Definition: frame.h:160
enum ast_frame_type frametype
Definition: frame.h:144
static void send_eivr_event(FILE *handle, const char event, const char *data, const struct ast_channel *chan)
#define ast_frfree(fr)
Definition: frame.h:583
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)
#define EIVR_CMD_HGUP
const ast_string_field language
Definition: channel.h:787
#define EIVR_CMD_GET
struct ast_channel * chan
int eivr_connect_socket ( struct ast_channel chan,
const char *  host,
int  port 
)
static void* gen_alloc ( struct ast_channel chan,
void *  params 
)
static

Definition at line 172 of file app_externalivr.c.

References ast_calloc, state, and gen_state::u.

173 {
174  struct ivr_localuser *u = params;
175  struct gen_state *state;
176 
177  if (!(state = ast_calloc(1, sizeof(*state))))
178  return NULL;
179 
180  state->u = u;
181 
182  return state;
183 }
enum sip_cc_notify_state state
Definition: chan_sip.c:842
struct ivr_localuser * u
#define ast_calloc(a, b)
Definition: astmm.h:82
static void gen_closestream ( struct gen_state state)
static

Definition at line 185 of file app_externalivr.c.

References ast_closestream(), ivr_localuser::chan, gen_state::stream, ast_channel::stream, and gen_state::u.

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

186 {
187  if (!state->stream)
188  return;
189 
190  ast_closestream(state->stream);
191  state->u->chan->stream = NULL;
192  state->stream = NULL;
193 }
struct ivr_localuser * u
struct ast_filestream * stream
int ast_closestream(struct ast_filestream *f)
Closes a stream.
Definition: file.c:904
struct ast_filestream * stream
Definition: channel.h:757
struct ast_channel * chan
static int gen_generate ( struct ast_channel chan,
void *  data,
int  len,
int  samples 
)
static

Definition at line 270 of file app_externalivr.c.

References ast_chan_log, ast_frfree, ast_write(), errno, f, gen_readframe(), LOG_WARNING, gen_state::sample_queue, and ast_frame::samples.

271 {
272  struct gen_state *state = data;
273  struct ast_frame *f = NULL;
274  int res = 0;
275 
276  state->sample_queue += samples;
277 
278  while (state->sample_queue > 0) {
279  if (!(f = gen_readframe(state)))
280  return -1;
281 
282  res = ast_write(chan, f);
283  ast_frfree(f);
284  if (res < 0) {
285  ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
286  return -1;
287  }
288  state->sample_queue -= f->samples;
289  }
290 
291  return res;
292 }
#define LOG_WARNING
Definition: logger.h:144
#define ast_chan_log(level, channel, format,...)
static struct ast_frame * gen_readframe(struct gen_state *state)
int errno
static struct ast_format f[]
Definition: format_g726.c:181
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:4916
Data structure associated with a single frame of data.
Definition: frame.h:142
#define ast_frfree(fr)
Definition: frame.h:583
int samples
Definition: frame.h:150
static int gen_nextfile ( struct gen_state state)
static

Definition at line 204 of file app_externalivr.c.

References ivr_localuser::abort_current_sound, ast_chan_log, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_openstream_full(), ivr_localuser::chan, gen_state::current, errno, playlist_entry::filename, gen_closestream(), ast_channel::language, LOG_WARNING, ivr_localuser::playing_silence, ivr_localuser::playlist, gen_state::stream, and gen_state::u.

Referenced by gen_readframe().

205 {
206  struct ivr_localuser *u = state->u;
207  char *file_to_stream;
208 
209  u->abort_current_sound = 0;
210  u->playing_silence = 0;
211  gen_closestream(state);
212 
213  while (!state->stream) {
214  state->current = AST_LIST_FIRST(&u->playlist);
215  if (state->current) {
216  file_to_stream = state->current->filename;
217  } else {
218  file_to_stream = "silence/10";
219  u->playing_silence = 1;
220  }
221 
222  if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) {
223  ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
224  AST_LIST_LOCK(&u->playlist);
225  AST_LIST_REMOVE_HEAD(&u->playlist, list);
227  if (!u->playing_silence) {
228  continue;
229  } else {
230  break;
231  }
232  }
233  }
234 
235  return (!state->stream);
236 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
struct ivr_localuser * u
struct ivr_localuser::playlist playlist
#define LOG_WARNING
Definition: logger.h:144
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
#define ast_chan_log(level, channel, format,...)
struct playlist_entry * current
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:641
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
static void gen_closestream(struct gen_state *state)
struct ast_filestream * stream
int errno
char filename[1]
const ast_string_field language
Definition: channel.h:787
struct ast_channel * chan
static struct ast_frame* gen_readframe ( struct gen_state state)
static

Definition at line 238 of file app_externalivr.c.

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(), gen_state::current, f, ivr_localuser::finishlist, gen_closestream(), gen_nextfile(), ivr_localuser::playing_silence, ivr_localuser::playlist, gen_state::stream, and gen_state::u.

Referenced by gen_generate().

239 {
240  struct ast_frame *f = NULL;
241  struct ivr_localuser *u = state->u;
242 
243  if (u->abort_current_sound ||
244  (u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
245  gen_closestream(state);
246  AST_LIST_LOCK(&u->playlist);
247  gen_nextfile(state);
249  }
250 
251  if (!(state->stream && (f = ast_readframe(state->stream)))) {
252  if (state->current) {
253  /* remove finished file from playlist */
254  AST_LIST_LOCK(&u->playlist);
255  AST_LIST_REMOVE_HEAD(&u->playlist, list);
257  /* add finished file to finishlist */
259  AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
261  state->current = NULL;
262  }
263  if (!gen_nextfile(state))
264  f = ast_readframe(state->stream);
265  }
266 
267  return f;
268 }
#define AST_LIST_LOCK(head)
Locks a list.
Definition: linkedlists.h:39
#define AST_LIST_FIRST(head)
Returns the first entry contained in a list.
Definition: linkedlists.h:420
struct ivr_localuser * u
struct ivr_localuser::playlist playlist
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
Definition: linkedlists.h:139
struct playlist_entry * current
static int gen_nextfile(struct gen_state *state)
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
Definition: linkedlists.h:818
static void gen_closestream(struct gen_state *state)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
Definition: linkedlists.h:716
struct ast_filestream * stream
struct ast_frame * ast_readframe(struct ast_filestream *s)
Read a frame from a filestream.
Definition: file.c:737
static struct ast_format f[]
Definition: format_g726.c:181
Data structure associated with a single frame of data.
Definition: frame.h:142
struct ivr_localuser::finishlist finishlist
static void gen_release ( struct ast_channel chan,
void *  data 
)
static

Definition at line 195 of file app_externalivr.c.

References ast_free, and gen_closestream().

196 {
197  struct gen_state *state = data;
198 
199  gen_closestream(state);
200  ast_free(data);
201 }
static void gen_closestream(struct gen_state *state)
#define ast_free(a)
Definition: astmm.h:97
static int load_module ( void  )
static

Definition at line 886 of file app_externalivr.c.

References app_exec(), and ast_register_application_xml.

887 {
889 }
static const char app[]
static int app_exec(struct ast_channel *chan, const char *data)
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Definition: module.h:437
static struct playlist_entry* make_entry ( const char *  filename)
static

Definition at line 377 of file app_externalivr.c.

References ast_calloc, and playlist_entry::filename.

Referenced by eivr_comm().

378 {
379  struct playlist_entry *entry;
380 
381  if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10))) /* XXX why 10 ? */
382  return NULL;
383 
384  strcpy(entry->filename, filename);
385 
386  return entry;
387 }
char filename[1]
#define ast_calloc(a, b)
Definition: astmm.h:82
static void send_eivr_event ( FILE *  handle,
const char  event,
const char *  data,
const struct ast_channel chan 
)
static

Definition at line 157 of file app_externalivr.c.

References ast_debug, ast_free, ast_str_append(), ast_str_buffer(), and ast_str_create().

Referenced by eivr_comm().

159 {
160  struct ast_str *tmp = ast_str_create(12);
161 
162  ast_str_append(&tmp, 0, "%c,%10d", event, (int)time(NULL));
163  if (data) {
164  ast_str_append(&tmp, 0, ",%s", data);
165  }
166 
167  fprintf(handle, "%s\n", ast_str_buffer(tmp));
168  ast_debug(1, "sent '%s'\n", ast_str_buffer(tmp));
169  ast_free(tmp);
170 }
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Definition: strings.h:497
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:900
struct ast_str * ast_str_create(size_t init_len)
Create a malloc&#39;ed dynamic length string.
Definition: strings.h:420
#define ast_debug(level,...)
Log a DEBUG message.
Definition: logger.h:236
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
Definition: strings.h:364
#define ast_free(a)
Definition: astmm.h:97
static int unload_module ( void  )
static

Definition at line 881 of file app_externalivr.c.

References ast_unregister_application().

882 {
884 }
static const char app[]
int ast_unregister_application(const char *app)
Unregister an application.
Definition: pbx.c:7705

Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_LOAD_ORDER , .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 = "ac1f6a56484a8820659555499174e588" , .load = load_module, .unload = unload_module, .load_pri = AST_MODPRI_DEFAULT, }
static

Definition at line 891 of file app_externalivr.c.

const char app[] = "ExternalIVR"
static

Definition at line 97 of file app_externalivr.c.

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

Definition at line 126 of file app_externalivr.c.

Referenced by app_exec().

Definition at line 891 of file app_externalivr.c.

struct ast_generator gen
static

Definition at line 294 of file app_externalivr.c.

Referenced by ast_activate_generator(), reload_config(), and set_config().