Wed Oct 28 11:45:44 2009

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 dependency graph for app_externalivr.c:

Go to the source code of this file.

Data Structures

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

Defines

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

Functions

static void __reg_module (void)
static void __unreg_module (void)
static int app_exec (struct ast_channel *chan, void *data)
static void ast_eivr_getvariable (struct ast_channel *chan, char *data, char *outbuf, int outbuflen)
static void ast_eivr_setvariable (struct ast_channel *chan, char *data)
static int eivr_comm (struct ast_channel *chan, struct ivr_localuser *u, int eivr_events_fd, int eivr_commands_fd, int eivr_errors_fd, const char *args)
static void * gen_alloc (struct ast_channel *chan, void *params)
static void gen_closestream (struct gen_state *state)
static int gen_generate (struct ast_channel *chan, void *data, int len, int samples)
static int gen_nextfile (struct gen_state *state)
static struct ast_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_DEFAULT , .description = "External IVR Interface Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, }
static const char * app = "ExternalIVR"
static const struct
ast_module_info
ast_module_info = &__mod_info
static const char * descrip
static struct ast_generator gen
static const char * synopsis = "Interfaces with an external IVR application"


Detailed Description

External IVR application interface.

Author:
Kevin P. Fleming <kpfleming@digium.com>
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.


Define Documentation

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

Definition at line 71 of file app_externalivr.c.

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


Function Documentation

static void __reg_module ( void   )  [static]

Definition at line 672 of file app_externalivr.c.

static void __unreg_module ( void   )  [static]

Definition at line 672 of file app_externalivr.c.

static int app_exec ( struct ast_channel chan,
void *  data 
) [static]

Definition at line 297 of file app_externalivr.c.

References ast_channel::_state, ivr_localuser::abort_current_sound, ast_activate_generator(), ast_answer(), AST_APP_ARG, ast_chan_log, ast_deactivate_generator(), AST_DECLARE_APP_ARGS, ast_free, AST_LIST_HEAD_INIT_VALUE, AST_LIST_REMOVE_HEAD, ast_log(), ast_opt_high_priority, ast_set_priority(), AST_STANDARD_APP_ARGS, AST_STATE_UP, ast_strdupa, ast_strlen_zero(), buf, ivr_localuser::chan, eivr_comm(), errno, LOG_WARNING, and ivr_localuser::playlist.

00298 {
00299    struct playlist_entry *entry;
00300    int child_stdin[2] = { 0,0 };
00301    int child_stdout[2] = { 0,0 };
00302    int child_stderr[2] = { 0,0 };
00303    int res = -1;
00304    int gen_active = 0;
00305    int pid;
00306    char *buf, *comma_delim_argbuf;
00307    struct ivr_localuser foo = {
00308       .playlist = AST_LIST_HEAD_INIT_VALUE,
00309       .finishlist = AST_LIST_HEAD_INIT_VALUE,
00310    };
00311    struct ivr_localuser *u = &foo;
00312    sigset_t fullset, oldset;
00313    AST_DECLARE_APP_ARGS(args,
00314       AST_APP_ARG(cmd)[32];
00315    );
00316 
00317    sigfillset(&fullset);
00318    pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
00319 
00320    u->abort_current_sound = 0;
00321    u->chan = chan;
00322 
00323    if (ast_strlen_zero(data)) {
00324       ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
00325       return -1;
00326    }
00327 
00328    buf = ast_strdupa(data);
00329    AST_STANDARD_APP_ARGS(args, buf);
00330 
00331    /* copy args and replace commas with pipes */
00332    comma_delim_argbuf = ast_strdupa(data);
00333    
00334    if (pipe(child_stdin)) {
00335       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
00336       goto exit;
00337    }
00338    if (pipe(child_stdout)) {
00339       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
00340       goto exit;
00341    }
00342    if (pipe(child_stderr)) {
00343       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
00344       goto exit;
00345    }
00346    if (chan->_state != AST_STATE_UP) {
00347       ast_answer(chan);
00348    }
00349    if (ast_activate_generator(chan, &gen, u) < 0) {
00350       ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
00351       goto exit;
00352    } else
00353       gen_active = 1;
00354 
00355    pid = fork();
00356    if (pid < 0) {
00357       ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
00358       goto exit;
00359    }
00360 
00361    if (!pid) {
00362       /* child process */
00363       int i;
00364 #ifdef HAVE_CAP
00365       cap_t cap = cap_from_text("cap_net_admin-eip");
00366 
00367       if (cap_set_proc(cap)) {
00368          /* Careful with order! Logging cannot happen after we close FDs */
00369          ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
00370       }
00371       cap_free(cap);
00372 #endif
00373 
00374       signal(SIGPIPE, SIG_DFL);
00375       pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
00376 
00377       if (ast_opt_high_priority)
00378          ast_set_priority(0);
00379 
00380       dup2(child_stdin[0], STDIN_FILENO);
00381       dup2(child_stdout[1], STDOUT_FILENO);
00382       dup2(child_stderr[1], STDERR_FILENO);
00383       for (i = STDERR_FILENO + 1; i < 1024; i++)
00384          close(i);
00385       execv(args.cmd[0], args.cmd);
00386       fprintf(stderr, "Failed to execute '%s': %s\n", args.cmd[0], strerror(errno));
00387       _exit(1);
00388    } else {
00389       /* parent process */
00390 
00391       close(child_stdin[0]);
00392       child_stdin[0] = 0;
00393       close(child_stdout[1]);
00394       child_stdout[1] = 0;
00395       close(child_stderr[1]);
00396       child_stderr[1] = 0;
00397       res = eivr_comm(chan, u, child_stdin[1], child_stdout[0], child_stderr[0], comma_delim_argbuf);
00398 
00399       exit:
00400       if (gen_active)
00401          ast_deactivate_generator(chan);
00402 
00403       if (child_stdin[0])
00404          close(child_stdin[0]);
00405 
00406       if (child_stdin[1])
00407          close(child_stdin[1]);
00408 
00409       if (child_stdout[0])
00410          close(child_stdout[0]);
00411 
00412       if (child_stdout[1])
00413          close(child_stdout[1]);
00414 
00415       if (child_stderr[0])
00416          close(child_stderr[0]);
00417 
00418       if (child_stderr[1])
00419          close(child_stderr[1]);
00420 
00421       while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
00422          ast_free(entry);
00423 
00424       return res;
00425    }
00426 }

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

Definition at line 236 of file app_externalivr.c.

References ast_copy_string(), ast_str_alloca, ast_str_append(), inbuf(), pbx_builtin_getvar_helper(), ast_str::str, and strsep().

Referenced by eivr_comm().

00237 {
00238    /* original input data: "G,var1,var2," */
00239    /* data passed as "data":  "var1,var2" */
00240 
00241    char *inbuf, *variable;
00242    const char *value;
00243    int j;
00244    struct ast_str *newstring = ast_str_alloca(outbuflen); 
00245 
00246    outbuf[0] = '\0';
00247 
00248    for (j = 1, inbuf = data; ; j++) {
00249       variable = strsep(&inbuf, ",");
00250       if (variable == NULL) {
00251          int outstrlen = strlen(outbuf);
00252          if(outstrlen && outbuf[outstrlen - 1] == ',') {
00253             outbuf[outstrlen - 1] = 0;
00254          }
00255          break;
00256       }
00257       
00258       value = pbx_builtin_getvar_helper(chan, variable);
00259       if(!value)
00260          value = "";
00261       ast_str_append(&newstring, 0, "%s=%s,", variable, value);
00262       ast_copy_string(outbuf, newstring->str, outbuflen);
00263    }
00264 };

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

Definition at line 266 of file app_externalivr.c.

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

Referenced by eivr_comm().

00267 {
00268    char *value;
00269 
00270    char *inbuf = ast_strdupa(data), *variable;
00271 
00272    for (variable = strsep(&inbuf, ","); variable; variable = strsep(&inbuf, ",")) {
00273       ast_debug(1, "Setting up a variable: %s\n", variable);
00274       /* variable contains "varname=value" */
00275       value = strchr(variable, '=');
00276       if (!value) {
00277          value = "";
00278       } else {
00279          *value++ = '\0';
00280       }
00281       pbx_builtin_setvar_helper(chan, variable, value);
00282    }
00283 };

static int eivr_comm ( struct ast_channel chan,
struct ivr_localuser u,
int  eivr_events_fd,
int  eivr_commands_fd,
int  eivr_errors_fd,
const char *  args 
) [static]

Todo:
add deprecation debug message for X command here

Definition at line 428 of file app_externalivr.c.

References ivr_localuser::abort_current_sound, ast_chan_log, ast_check_hangup(), AST_CONTROL_HANGUP, ast_eivr_getvariable(), ast_eivr_setvariable(), ast_fileexists(), AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_free, ast_frfree, AST_LIST_EMPTY, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_read(), ast_strip(), ast_test_flag, ast_waitfor_nandfds(), ivr_localuser::chan, errno, f, playlist_entry::filename, ivr_localuser::finishlist, ast_frame::frametype, input(), ast_channel::language, LOG_DEBUG, LOG_NOTICE, LOG_WARNING, make_entry(), ivr_localuser::option_autoclear, option_debug, ivr_localuser::playing_silence, ivr_localuser::playlist, send_eivr_event(), and ast_frame::subclass.

Referenced by app_exec().

00431 {
00432    struct playlist_entry *entry;
00433    struct ast_frame *f;
00434    int ms;
00435    int exception;
00436    int ready_fd;
00437    int waitfds[2] = { eivr_commands_fd, eivr_errors_fd };
00438    struct ast_channel *rchan;
00439    char *command;
00440    int res = -1;
00441    int test_available_fd = -1;
00442   
00443    FILE *eivr_commands = NULL;
00444    FILE *eivr_errors = NULL;
00445    FILE *eivr_events = NULL;
00446  
00447    if (!(eivr_events = fdopen(eivr_events_fd, "w"))) {
00448       ast_chan_log(LOG_WARNING, chan, "Could not open stream to send events\n");
00449       goto exit;
00450    }
00451    if (!(eivr_commands = fdopen(eivr_commands_fd, "r"))) {
00452       ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive commands\n");
00453       goto exit;
00454    }
00455    if(eivr_errors_fd) {  /*if opening a socket connection, error stream will not be used*/
00456       if (!(eivr_errors = fdopen(eivr_errors_fd, "r"))) {
00457          ast_chan_log(LOG_WARNING, chan, "Could not open stream to receive errors\n");
00458          goto exit;
00459       }
00460    }
00461 
00462    test_available_fd = open("/dev/null", O_RDONLY);
00463  
00464    setvbuf(eivr_events, NULL, _IONBF, 0);
00465    setvbuf(eivr_commands, NULL, _IONBF, 0);
00466    if(eivr_errors)
00467       setvbuf(eivr_errors, NULL, _IONBF, 0);
00468 
00469    res = 0;
00470  
00471    while (1) {
00472       if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
00473          ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
00474          res = -1;
00475          break;
00476       }
00477       if (ast_check_hangup(chan)) {
00478          ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
00479          send_eivr_event(eivr_events, 'H', NULL, chan);
00480          res = -1;
00481          break;
00482       }
00483  
00484       ready_fd = 0;
00485       ms = 100;
00486       errno = 0;
00487       exception = 0;
00488  
00489       rchan = ast_waitfor_nandfds(&chan, 1, waitfds, (eivr_errors_fd == 0) ? 1 : 2, &exception, &ready_fd, &ms);
00490  
00491       if (!AST_LIST_EMPTY(&u->finishlist)) {
00492          AST_LIST_LOCK(&u->finishlist);
00493          while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
00494             send_eivr_event(eivr_events, 'F', entry->filename, chan);
00495             ast_free(entry);
00496          }
00497          AST_LIST_UNLOCK(&u->finishlist);
00498       }
00499  
00500       if (rchan) {
00501          /* the channel has something */
00502          f = ast_read(chan);
00503          if (!f) {
00504             ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
00505             send_eivr_event(eivr_events, 'H', NULL, chan);
00506             res = -1;
00507             break;
00508          }
00509          if (f->frametype == AST_FRAME_DTMF) {
00510             send_eivr_event(eivr_events, f->subclass, NULL, chan);
00511             if (u->option_autoclear) {
00512                if (!u->abort_current_sound && !u->playing_silence)
00513                   send_eivr_event(eivr_events, 'T', NULL, chan);
00514                AST_LIST_LOCK(&u->playlist);
00515                while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00516                   send_eivr_event(eivr_events, 'D', entry->filename, chan);
00517                   ast_free(entry);
00518                }
00519                if (!u->playing_silence)
00520                   u->abort_current_sound = 1;
00521                AST_LIST_UNLOCK(&u->playlist);
00522             }
00523          } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
00524             ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
00525             send_eivr_event(eivr_events, 'H', NULL, chan);
00526             ast_frfree(f);
00527             res = -1;
00528             break;
00529          }
00530          ast_frfree(f);
00531       } else if (ready_fd == eivr_commands_fd) {
00532          char input[1024];
00533  
00534          if (exception || (dup2(eivr_commands_fd, test_available_fd) == -1) || feof(eivr_commands)) {
00535             ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00536             res = -1;
00537             break;
00538          }
00539   
00540          if (!fgets(input, sizeof(input), eivr_commands))
00541             continue;
00542  
00543          command = ast_strip(input);
00544   
00545          if (option_debug)
00546             ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input);
00547   
00548          if (strlen(input) < 4)
00549             continue;
00550   
00551          if (input[0] == 'P') {
00552             send_eivr_event(eivr_events, 'P', args, chan);
00553  
00554          } else if (input[0] == 'S') {
00555             if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00556                ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00557                send_eivr_event(eivr_events, 'Z', NULL, chan);
00558                strcpy(&input[2], "exception");
00559             }
00560             if (!u->abort_current_sound && !u->playing_silence)
00561                send_eivr_event(eivr_events, 'T', NULL, chan);
00562             AST_LIST_LOCK(&u->playlist);
00563             while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
00564                send_eivr_event(eivr_events, 'D', entry->filename, chan);
00565                ast_free(entry);
00566             }
00567             if (!u->playing_silence)
00568                u->abort_current_sound = 1;
00569             entry = make_entry(&input[2]);
00570             if (entry)
00571                AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00572             AST_LIST_UNLOCK(&u->playlist);
00573          } else if (input[0] == 'A') {
00574             if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
00575                ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
00576                send_eivr_event(eivr_events, 'Z', NULL, chan);
00577                strcpy(&input[2], "exception");
00578             }
00579             entry = make_entry(&input[2]);
00580             if (entry) {
00581                AST_LIST_LOCK(&u->playlist);
00582                AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
00583                AST_LIST_UNLOCK(&u->playlist);
00584             }
00585          } else if (input[0] == 'G') {
00586             /* A get variable message:  "G,variable1,variable2,..." */
00587             char response[2048];
00588 
00589             ast_chan_log(LOG_NOTICE, chan, "Getting a Variable out of the channel: %s\n", &input[2]);
00590             ast_eivr_getvariable(chan, &input[2], response, sizeof(response));
00591             send_eivr_event(eivr_events, 'G', response, chan);
00592          } else if (input[0] == 'V') {
00593             /* A set variable message:  "V,variablename=foo" */
00594             ast_chan_log(LOG_NOTICE, chan, "Setting a Variable up: %s\n", &input[2]);
00595             ast_eivr_setvariable(chan, &input[2]);
00596          } else if (input[0] == 'L') {
00597             ast_chan_log(LOG_NOTICE, chan, "Log message from EIVR: %s\n", &input[2]);
00598          } else if (input[0] == 'X') {
00599             ast_chan_log(LOG_NOTICE, chan, "Exiting ExternalIVR: %s\n", &input[2]);
00600             /*! \todo add deprecation debug message for X command here */
00601             res = 0;
00602             break;
00603          } else if (input[0] == 'E') {
00604             ast_chan_log(LOG_NOTICE, chan, "Exiting: %s\n", &input[2]);
00605             send_eivr_event(eivr_events, 'E', NULL, chan);
00606             res = 0;
00607             break;
00608          } else if (input[0] == 'H') {
00609             ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
00610             send_eivr_event(eivr_events, 'H', NULL, chan);
00611             res = -1;
00612             break;
00613          } else if (input[0] == 'O') {
00614             if (!strcasecmp(&input[2], "autoclear"))
00615                u->option_autoclear = 1;
00616             else if (!strcasecmp(&input[2], "noautoclear"))
00617                u->option_autoclear = 0;
00618             else
00619                ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
00620          }
00621       } else if (eivr_errors_fd && ready_fd == eivr_errors_fd) {
00622          char input[1024];
00623   
00624          if (exception || feof(eivr_errors)) {
00625             ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
00626             res = -1;
00627             break;
00628          }
00629          if (fgets(input, sizeof(input), eivr_errors)) {
00630             command = ast_strip(input);
00631             ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
00632          }
00633       } else if ((ready_fd < 0) && ms) { 
00634          if (errno == 0 || errno == EINTR)
00635             continue;
00636  
00637          ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
00638          break;
00639       }
00640    }
00641   
00642  
00643 exit:
00644  
00645    if (test_available_fd > -1) {
00646       close(test_available_fd);
00647    }
00648 
00649    if (eivr_events)
00650       fclose(eivr_events);
00651  
00652    if (eivr_commands)
00653       fclose(eivr_commands);
00654 
00655    if (eivr_errors)
00656       fclose(eivr_errors);
00657   
00658    return res;
00659  
00660   }

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

Definition at line 115 of file app_externalivr.c.

References ast_calloc, and gen_state::u.

00116 {
00117    struct ivr_localuser *u = params;
00118    struct gen_state *state;
00119 
00120    if (!(state = ast_calloc(1, sizeof(*state))))
00121       return NULL;
00122 
00123    state->u = u;
00124 
00125    return state;
00126 }

static void gen_closestream ( struct gen_state state  )  [static]

Definition at line 128 of file app_externalivr.c.

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

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

00129 {
00130    if (!state->stream)
00131       return;
00132 
00133    ast_closestream(state->stream);
00134    state->u->chan->stream = NULL;
00135    state->stream = NULL;
00136 }

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

Definition at line 205 of file app_externalivr.c.

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

00206 {
00207    struct gen_state *state = data;
00208    struct ast_frame *f = NULL;
00209    int res = 0;
00210 
00211    state->sample_queue += samples;
00212 
00213    while (state->sample_queue > 0) {
00214       if (!(f = gen_readframe(state)))
00215          return -1;
00216 
00217       res = ast_write(chan, f);
00218       ast_frfree(f);
00219       if (res < 0) {
00220          ast_chan_log(LOG_WARNING, chan, "Failed to write frame: %s\n", strerror(errno));
00221          return -1;
00222       }
00223       state->sample_queue -= f->samples;
00224    }
00225 
00226    return res;
00227 }

static int gen_nextfile ( struct gen_state state  )  [static]

Definition at line 147 of file app_externalivr.c.

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

Referenced by gen_readframe().

00148 {
00149    struct ivr_localuser *u = state->u;
00150    char *file_to_stream;
00151 
00152    u->abort_current_sound = 0;
00153    u->playing_silence = 0;
00154    gen_closestream(state);
00155 
00156    while (!state->stream) {
00157       state->current = AST_LIST_REMOVE_HEAD(&u->playlist, list);
00158       if (state->current) {
00159          file_to_stream = state->current->filename;
00160       } else {
00161          file_to_stream = "silence/10";
00162          u->playing_silence = 1;
00163       }
00164 
00165       if (!(state->stream = ast_openstream_full(u->chan, file_to_stream, u->chan->language, 1))) {
00166          ast_chan_log(LOG_WARNING, u->chan, "File '%s' could not be opened: %s\n", file_to_stream, strerror(errno));
00167          if (!u->playing_silence) {
00168             continue;
00169          } else {
00170             break;
00171          }
00172       }
00173    }
00174 
00175    return (!state->stream);
00176 }

static struct ast_frame* gen_readframe ( struct gen_state state  )  [static, read]

Definition at line 178 of file app_externalivr.c.

References ivr_localuser::abort_current_sound, AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_readframe(), gen_state::current, f, ivr_localuser::finishlist, gen_closestream(), gen_nextfile(), ivr_localuser::playing_silence, ivr_localuser::playlist, gen_state::stream, and gen_state::u.

Referenced by gen_generate().

00179 {
00180    struct ast_frame *f = NULL;
00181    struct ivr_localuser *u = state->u;
00182 
00183    if (u->abort_current_sound ||
00184       (u->playing_silence && AST_LIST_FIRST(&u->playlist))) {
00185       gen_closestream(state);
00186       AST_LIST_LOCK(&u->playlist);
00187       gen_nextfile(state);
00188       AST_LIST_UNLOCK(&u->playlist);
00189    }
00190 
00191    if (!(state->stream && (f = ast_readframe(state->stream)))) {
00192       if (state->current) {
00193          AST_LIST_LOCK(&u->finishlist);
00194          AST_LIST_INSERT_TAIL(&u->finishlist, state->current, list);
00195          AST_LIST_UNLOCK(&u->finishlist);
00196          state->current = NULL;
00197       }
00198       if (!gen_nextfile(state))
00199          f = ast_readframe(state->stream);
00200    }
00201 
00202    return f;
00203 }

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

Definition at line 138 of file app_externalivr.c.

References ast_free, and gen_closestream().

00139 {
00140    struct gen_state *state = data;
00141 
00142    gen_closestream(state);
00143    ast_free(data);
00144 }

static int load_module ( void   )  [static]

Definition at line 667 of file app_externalivr.c.

References app_exec, and ast_register_application.

00668 {
00669    return ast_register_application(app, app_exec, synopsis, descrip);
00670 }

static struct playlist_entry* make_entry ( const char *  filename  )  [static, read]

Definition at line 285 of file app_externalivr.c.

References ast_calloc, and playlist_entry::filename.

Referenced by eivr_comm().

00286 {
00287    struct playlist_entry *entry;
00288 
00289    if (!(entry = ast_calloc(1, sizeof(*entry) + strlen(filename) + 10))) /* XXX why 10 ? */
00290       return NULL;
00291 
00292    strcpy(entry->filename, filename);
00293 
00294    return entry;
00295 }

static void send_eivr_event ( FILE *  handle,
const char  event,
const char *  data,
const struct ast_channel chan 
) [static]

Definition at line 99 of file app_externalivr.c.

References ast_chan_log, LOG_DEBUG, and option_debug.

Referenced by eivr_comm().

00101 {
00102    char tmp[256];
00103 
00104    if (!data) {
00105       snprintf(tmp, sizeof(tmp), "%c,%10d", event, (int)time(NULL));
00106    } else {
00107       snprintf(tmp, sizeof(tmp), "%c,%10d,%s", event, (int)time(NULL), data);
00108    }
00109 
00110    fprintf(handle, "%s\n", tmp);
00111    if (option_debug)
00112       ast_chan_log(LOG_DEBUG, chan, "sent '%s'\n", tmp);
00113 }

static int unload_module ( void   )  [static]

Definition at line 662 of file app_externalivr.c.

References ast_unregister_application().

00663 {
00664    return ast_unregister_application(app);
00665 }


Variable Documentation

struct ast_module_info __mod_info = { .name = AST_MODULE, .flags = AST_MODFLAG_DEFAULT , .description = "External IVR Interface Application" , .key = "This paragraph is copyright (c) 2006 by Digium, Inc. \In order for your module to load, it must return this \key via a function called \"key\". Any code which \includes this paragraph must be licensed under the GNU \General Public License version 2 or later (at your \option). In addition to Digium's general reservations \of rights, Digium expressly reserves the right to \allow other parties to license this paragraph under \different terms. Any use of Digium, Inc. trademarks or \logos (including \"Asterisk\" or \"Digium\") without \express written permission of Digium, Inc. is prohibited.\n" , .buildopt_sum = AST_BUILDOPT_SUM, .load = load_module, .unload = unload_module, } [static]

Definition at line 672 of file app_externalivr.c.

const char* app = "ExternalIVR" [static]

Definition at line 56 of file app_externalivr.c.

const struct ast_module_info* ast_module_info = &__mod_info [static]

Definition at line 672 of file app_externalivr.c.

const char* descrip [static]

Definition at line 60 of file app_externalivr.c.

struct ast_generator gen [static]

Definition at line 229 of file app_externalivr.c.

Referenced by reload_config(), and set_config().

const char* synopsis = "Interfaces with an external IVR application" [static]

Definition at line 58 of file app_externalivr.c.


Generated on Wed Oct 28 11:45:44 2009 for Asterisk - the Open Source PBX by  doxygen 1.5.6