Asterisk.org: Developer Documentation (28 Oct 2009)

Wed Oct 28 15:48:04 2009

## Asterisk developer's documentation

# app_externalivr.c File Reference

External IVR application interface. More...

`#include <stdlib.h>`
`#include <stdio.h>`
`#include <string.h>`
`#include <unistd.h>`
`#include <errno.h>`
`#include <signal.h>`
`#include "asterisk.h"`
`#include "asterisk/lock.h"`
`#include "asterisk/file.h"`
`#include "asterisk/logger.h"`
`#include "asterisk/channel.h"`
`#include "asterisk/pbx.h"`
`#include "asterisk/module.h"`
`#include "asterisk/linkedlists.h"`
`#include "asterisk/app.h"`
`#include "asterisk/options.h"`

Include dependency graph for app_externalivr.c:

Go to the source code of this file.

## Data Structures

struct | gen_state
struct | localuser
| We define a custom "local user" structure because we use it not only for keeping track of what is in use but also for keeping track of who we're dialing. More...
struct | playlist_entry

## Defines

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

## Functions

static int | app_exec (struct ast_channel *chan, void *data)
char * | description (void)
| Provides a description of the module.
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_frame * | gen_readframe (struct gen_state *state)
static void | gen_release (struct ast_channel *chan, void *data)
char * | key ()
| Returns the ASTERISK_GPL_KEY.
int | load_module (void)
| Initialize the module.
static struct playlist_entry * | make_entry (const char *filename)
static void | send_child_event (FILE *handle, const char event, const char *data, const struct ast_channel *chan)
int | unload_module (void)
| Cleanup all module structures, sockets, etc.
int | usecount (void)
| Provides a usecount.

## Variables

static const char * | app = "ExternalIVR"
static const char * | descrip
static struct ast_generator | gen
| LOCAL_USER_DECL
static const char * | synopsis = "Interfaces with an external IVR application"
static const char * | tdesc = "External IVR Interface Application"

## Detailed Description

External IVR application interface.

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 67 of file app_externalivr.c.

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

## Function Documentation

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

Definition at line 245 of file app_externalivr.c.

References ast_channel::_state, ast_activate_generator(), ast_answer(), ast_app_separate_args(), ast_chan_log, ast_check_hangup(), AST_CONTROL_HANGUP, ast_deactivate_generator(), ast_fileexists(), AST_FLAG_ZOMBIE, AST_FRAME_CONTROL, AST_FRAME_DTMF, ast_frfree(), AST_LIST_EMPTY, AST_LIST_HEAD_INIT, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_HEAD, AST_LIST_UNLOCK, ast_log(), ast_read(), ast_set_priority(), AST_STATE_UP, ast_strdupa, ast_strlen_zero(), ast_test_flag, ast_waitfor_nandfds(), localuser::chan, ast_frame::frametype, free, gen, input(), ast_channel::language, list, LOCAL_USER_ADD, LOCAL_USER_REMOVE, LOG_DEBUG, LOG_ERROR, LOG_NOTICE, LOG_WARNING, make_entry(), option_highpriority, send_child_event(), and ast_frame::subclass.

    00246 {
    00247    struct localuser *u = NULL;
    00248    struct playlist_entry *entry;
    00249    const char *args = data;
    00250    int child_stdin[2] = { 0,0 };
    00251    int child_stdout[2] = { 0,0 };
    00252    int child_stderr[2] = { 0,0 };
    00253    int res = -1;
    00254    int gen_active = 0;
    00255    int pid;
    00256    char *argv[32];
    00257    int argc = 1;
    00258    char *buf, *command;
    00259    FILE *child_commands = NULL;
    00260    FILE *child_errors = NULL;
    00261    FILE *child_events = NULL;
    00262    sigset_t fullset, oldset;
    00263
    00264    LOCAL_USER_ADD(u);
    00265
    00266    sigfillset(&fullset);
    00267    pthread_sigmask(SIG_BLOCK, &fullset, &oldset);
    00268
    00269    AST_LIST_HEAD_INIT(&u->playlist);
    00270    AST_LIST_HEAD_INIT(&u->finishlist);
    00271    u->abort_current_sound = 0;
    00272
    00273    if (ast_strlen_zero(args)) {
    00274       ast_log(LOG_WARNING, "ExternalIVR requires a command to execute\n");
    00275       goto exit;
    00276    }
    00277
    00278    buf = ast_strdupa(data);
    00279    if (!buf) {
    00280       ast_log(LOG_ERROR, "Out of memory!\n");
    00281       LOCAL_USER_REMOVE(u);
    00282       return -1;
    00283    }
    00284
    00285    argc = ast_app_separate_args(buf, '|', argv, sizeof(argv) / sizeof(argv[0]));
    00286
    00287    if (pipe(child_stdin)) {
    00288       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child input: %s\n", strerror(errno));
    00289       goto exit;
    00290    }
    00291
    00292    if (pipe(child_stdout)) {
    00293       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child output: %s\n", strerror(errno));
    00294       goto exit;
    00295    }
    00296
    00297    if (pipe(child_stderr)) {
    00298       ast_chan_log(LOG_WARNING, chan, "Could not create pipe for child errors: %s\n", strerror(errno));
    00299       goto exit;
    00300    }
    00301
    00302    if (chan->_state != AST_STATE_UP) {
    00303       ast_answer(chan);
    00304    }
    00305
    00306    if (ast_activate_generator(chan, &gen, u) < 0) {
    00307       ast_chan_log(LOG_WARNING, chan, "Failed to activate generator\n");
    00308       goto exit;
    00309    } else
    00310       gen_active = 1;
    00311
    00312    pid = fork();
    00313    if (pid < 0) {
    00314       ast_log(LOG_WARNING, "Failed to fork(): %s\n", strerror(errno));
    00315       goto exit;
    00316    }
    00317
    00318    if (!pid) {
    00319       /* child process */
    00320       int i;
    00321
    00322       signal(SIGPIPE, SIG_DFL);
    00323       pthread_sigmask(SIG_UNBLOCK, &fullset, NULL);
    00324
    00325       if (option_highpriority)
    00326          ast_set_priority(0);
    00327
    00328       dup2(child_stdin[0], STDIN_FILENO);
    00329       dup2(child_stdout[1], STDOUT_FILENO);
    00330       dup2(child_stderr[1], STDERR_FILENO);
    00331       for (i = STDERR_FILENO + 1; i < 1024; i++)
    00332          close(i);
    00333       execv(argv[0], argv);
    00334       fprintf(stderr, "Failed to execute '%s': %s\n", argv[0], strerror(errno));
    00335       _exit(1);
    00336    } else {
    00337       /* parent process */
    00338       int child_events_fd = child_stdin[1];
    00339       int child_commands_fd = child_stdout[0];
    00340       int child_errors_fd = child_stderr[0];
    00341       struct ast_frame *f;
    00342       int ms;
    00343       int exception;
    00344       int ready_fd;
    00345       int waitfds[2] = { child_errors_fd, child_commands_fd };
    00346       struct ast_channel *rchan;
    00347
    00348       pthread_sigmask(SIG_SETMASK, &oldset, NULL);
    00349
    00350       close(child_stdin[0]);
    00351       child_stdin[0] = 0;
    00352       close(child_stdout[1]);
    00353       child_stdout[1] = 0;
    00354       close(child_stderr[1]);
    00355       child_stderr[1] = 0;
    00356
    00357       if (!(child_events = fdopen(child_events_fd, "w"))) {
    00358          ast_chan_log(LOG_WARNING, chan, "Could not open stream for child events\n");
    00359          goto exit;
    00360       }
    00361
    00362       if (!(child_commands = fdopen(child_commands_fd, "r"))) {
    00363          ast_chan_log(LOG_WARNING, chan, "Could not open stream for child commands\n");
    00364          goto exit;
    00365       }
    00366
    00367       if (!(child_errors = fdopen(child_errors_fd, "r"))) {
    00368          ast_chan_log(LOG_WARNING, chan, "Could not open stream for child errors\n");
    00369          goto exit;
    00370       }
    00371
    00372       setvbuf(child_events, NULL, _IONBF, 0);
    00373       setvbuf(child_commands, NULL, _IONBF, 0);
    00374       setvbuf(child_errors, NULL, _IONBF, 0);
    00375
    00376       res = 0;
    00377
    00378       while (1) {
    00379          if (ast_test_flag(chan, AST_FLAG_ZOMBIE)) {
    00380             ast_chan_log(LOG_NOTICE, chan, "Is a zombie\n");
    00381             res = -1;
    00382             break;
    00383          }
    00384
    00385          if (ast_check_hangup(chan)) {
    00386             ast_chan_log(LOG_NOTICE, chan, "Got check_hangup\n");
    00387             send_child_event(child_events, 'H', NULL, chan);
    00388             res = -1;
    00389             break;
    00390          }
    00391
    00392          ready_fd = 0;
    00393          ms = 100;
    00394          errno = 0;
    00395          exception = 0;
    00396
    00397          rchan = ast_waitfor_nandfds(&chan, 1, waitfds, 2, &exception, &ready_fd, &ms);
    00398
    00399          if (!AST_LIST_EMPTY(&u->finishlist)) {
    00400             AST_LIST_LOCK(&u->finishlist);
    00401             while ((entry = AST_LIST_REMOVE_HEAD(&u->finishlist, list))) {
    00402                send_child_event(child_events, 'F', entry->filename, chan);
    00403                free(entry);
    00404             }
    00405             AST_LIST_UNLOCK(&u->finishlist);
    00406          }
    00407
    00408          if (rchan) {
    00409             /* the channel has something */
    00410             f = ast_read(chan);
    00411             if (!f) {
    00412                ast_chan_log(LOG_NOTICE, chan, "Returned no frame\n");
    00413                send_child_event(child_events, 'H', NULL, chan);
    00414                res = -1;
    00415                break;
    00416             }
    00417
    00418             if (f->frametype == AST_FRAME_DTMF) {
    00419                send_child_event(child_events, f->subclass, NULL, chan);
    00420                if (u->option_autoclear) {
    00421                   if (!u->abort_current_sound && !u->playing_silence)
    00422                      send_child_event(child_events, 'T', NULL, chan);
    00423                   AST_LIST_LOCK(&u->playlist);
    00424                   while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
    00425                      send_child_event(child_events, 'D', entry->filename, chan);
    00426                      free(entry);
    00427                   }
    00428                   if (!u->playing_silence)
    00429                      u->abort_current_sound = 1;
    00430                   AST_LIST_UNLOCK(&u->playlist);
    00431                }
    00432             } else if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
    00433                ast_chan_log(LOG_NOTICE, chan, "Got AST_CONTROL_HANGUP\n");
    00434                send_child_event(child_events, 'H', NULL, chan);
    00435                ast_frfree(f);
    00436                res = -1;
    00437                break;
    00438             }
    00439             ast_frfree(f);
    00440          } else if (ready_fd == child_commands_fd) {
    00441             char input[1024];
    00442
    00443             if (exception || feof(child_commands)) {
    00444                ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
    00445                res = -1;
    00446                break;
    00447             }
    00448
    00449             if (!fgets(input, sizeof(input), child_commands))
    00450                continue;
    00451
    00452             command = ast_strip(input);
    00453
    00454             ast_chan_log(LOG_DEBUG, chan, "got command '%s'\n", input);
    00455
    00456             if (strlen(input) < 4)
    00457                continue;
    00458
    00459             if (input[0] == 'S') {
    00460                if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
    00461                   ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
    00462                   send_child_event(child_events, 'Z', NULL, chan);
    00463                   strcpy(&input[2], "exception");
    00464                }
    00465                if (!u->abort_current_sound && !u->playing_silence)
    00466                   send_child_event(child_events, 'T', NULL, chan);
    00467                AST_LIST_LOCK(&u->playlist);
    00468                while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list))) {
    00469                   send_child_event(child_events, 'D', entry->filename, chan);
    00470                   free(entry);
    00471                }
    00472                if (!u->playing_silence)
    00473                   u->abort_current_sound = 1;
    00474                entry = make_entry(&input[2]);
    00475                if (entry)
    00476                   AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
    00477                AST_LIST_UNLOCK(&u->playlist);
    00478             } else if (input[0] == 'A') {
    00479                if (ast_fileexists(&input[2], NULL, u->chan->language) == -1) {
    00480                   ast_chan_log(LOG_WARNING, chan, "Unknown file requested '%s'\n", &input[2]);
    00481                   send_child_event(child_events, 'Z', NULL, chan);
    00482                   strcpy(&input[2], "exception");
    00483                }
    00484                entry = make_entry(&input[2]);
    00485                if (entry) {
    00486                   AST_LIST_LOCK(&u->playlist);
    00487                   AST_LIST_INSERT_TAIL(&u->playlist, entry, list);
    00488                   AST_LIST_UNLOCK(&u->playlist);
    00489                }
    00490             } else if (input[0] == 'H') {
    00491                ast_chan_log(LOG_NOTICE, chan, "Hanging up: %s\n", &input[2]);
    00492                send_child_event(child_events, 'H', NULL, chan);
    00493                break;
    00494             } else if (input[0] == 'O') {
    00495                if (!strcasecmp(&input[2], "autoclear"))
    00496                   u->option_autoclear = 1;
    00497                else if (!strcasecmp(&input[2], "noautoclear"))
    00498                   u->option_autoclear = 0;
    00499                else
    00500                   ast_chan_log(LOG_WARNING, chan, "Unknown option requested '%s'\n", &input[2]);
    00501             }
    00502          } else if (ready_fd == child_errors_fd) {
    00503             char input[1024];
    00504
    00505             if (exception || feof(child_errors)) {
    00506                ast_chan_log(LOG_WARNING, chan, "Child process went away\n");
    00507                res = -1;
    00508                break;
    00509             }
    00510
    00511             if (fgets(input, sizeof(input), child_errors)) {
    00512                command = ast_strip(input);
    00513                ast_chan_log(LOG_NOTICE, chan, "stderr: %s\n", command);
    00514             }
    00515          } else if ((ready_fd < 0) && ms) {
    00516             if (errno == 0 || errno == EINTR)
    00517                continue;
    00518
    00519             ast_chan_log(LOG_WARNING, chan, "Wait failed (%s)\n", strerror(errno));
    00520             break;
    00521          }
    00522       }
    00523    }
    00524
    00525  exit:
    00526    if (gen_active)
    00527       ast_deactivate_generator(chan);
    00528
    00529    if (child_events)
    00530       fclose(child_events);
    00531
    00532    if (child_commands)
    00533       fclose(child_commands);
    00534
    00535    if (child_errors)
    00536       fclose(child_errors);
    00537
    00538    if (child_stdin[0])
    00539       close(child_stdin[0]);
    00540
    00541    if (child_stdin[1])
    00542       close(child_stdin[1]);
    00543
    00544    if (child_stdout[0])
    00545       close(child_stdout[0]);
    00546
    00547    if (child_stdout[1])
    00548       close(child_stdout[1]);
    00549
    00550    if (child_stderr[0])
    00551       close(child_stderr[0]);
    00552
    00553    if (child_stderr[1])
    00554       close(child_stderr[1]);
    00555
    00556    while ((entry = AST_LIST_REMOVE_HEAD(&u->playlist, list)))
    00557       free(entry);
    00558
    00559    LOCAL_USER_REMOVE(u);
    00560
    00561    return res;
    00562 }

char* description | ( | void |  | ) |

Provides a description of the module.

Returns:
  a short description of your module

Definition at line 580 of file app_externalivr.c.

    00581 {
    00582    return (char *) tdesc;
    00583 }

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

Definition at line 108 of file app_externalivr.c.

References calloc, and gen_state::u.

    00109 {
    00110    struct localuser *u = params;
    00111    struct gen_state *state;
    00112
    00113    state = calloc(1, sizeof(*state));
    00114
    00115    if (!state)
    00116       return NULL;
    00117
    00118    state->u = u;
    00119
    00120    return state;
    00121 }

static void gen_closestream | ( | struct gen_state * | state | ) | `[static]`

Definition at line 123 of file app_externalivr.c.

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

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

    00124 {
    00125    if (!state->stream)
    00126       return;
    00127
    00128    ast_closestream(state->stream);
    00129    state->u->chan->stream = NULL;
    00130    state->stream = NULL;
    00131 }

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

Definition at line 200 of file app_externalivr.c.

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

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

static int gen_nextfile | ( | struct gen_state * | state | ) | `[static]`

Definition at line 142 of file app_externalivr.c.

References ast_chan_log, AST_LIST_REMOVE_HEAD, ast_openstream_full(), localuser::chan, gen_state::current, gen_closestream(), ast_channel::language, list, LOG_WARNING, gen_state::stream, and gen_state::u.

Referenced by gen_readframe().

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

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

Definition at line 173 of file app_externalivr.c.

References AST_LIST_FIRST, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_readframe(), gen_state::current, gen_closestream(), gen_nextfile(), list, gen_state::stream, and gen_state::u.

Referenced by gen_generate().

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

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

Definition at line 133 of file app_externalivr.c.

References free, and gen_closestream().

    00134 {
    00135    struct gen_state *state = data;
    00136
    00137    gen_closestream(state);
    00138    free(data);
    00139 }

char* key | ( | void |  | ) |

Returns the ASTERISK_GPL_KEY.

This returns the ASTERISK_GPL_KEY, signifiying that you agree to the terms of the GPL stated in the ASTERISK_GPL_KEY. Your module will not load if it does not return the EXACT message:

     char *key(void) {
             return ASTERISK_GPL_KEY;
     }

Returns:
  ASTERISK_GPL_KEY

Definition at line 594 of file app_externalivr.c.

References ASTERISK_GPL_KEY.

    00595 {
    00596    return ASTERISK_GPL_KEY;
    00597 }

int load_module | ( | void |  | ) |

Initialize the module.

This function is called at module load time. Put all code in here that needs to set up your module's hardware, software, registrations, etc.

Returns:
  This function should return 0 on success and non-zero on failure. If the module is not loaded successfully, Asterisk will call its unload_module() function.

Initialize the Agents module. This function is being called by Asterisk when loading the module. Among other thing it registers applications, cli commands and reads the cofiguration file.

Returns:
  int Always 0.

TE STUFF END

Definition at line 575 of file app_externalivr.c.

References app_exec, and ast_register_application().

    00576 {
    00577    return ast_register_application(app, app_exec, synopsis, descrip);
    00578 }

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

Definition at line 231 of file app_externalivr.c.

References calloc.

Referenced by app_exec().

    00232 {
    00233    struct playlist_entry *entry;
    00234
    00235    entry = calloc(1, sizeof(*entry) + strlen(filename) + 10);
    00236
    00237    if (!entry)
    00238       return NULL;
    00239
    00240    strcpy(entry->filename, filename);
    00241
    00242    return entry;
    00243 }

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

Definition at line 93 of file app_externalivr.c.

References ast_chan_log, and LOG_DEBUG.

Referenced by app_exec().

    00095 {
    00096    char tmp[256];
    00097
    00098    if (!data) {
    00099       snprintf(tmp, sizeof(tmp), "%c,%10d", event, (int)time(NULL));
    00100    } else {
    00101       snprintf(tmp, sizeof(tmp), "%c,%10d,%s", event, (int)time(NULL), data);
    00102    }
    00103
    00104    fprintf(handle, "%s\n", tmp);
    00105    ast_chan_log(LOG_DEBUG, chan, "sent '%s'\n", tmp);
    00106 }

int unload_module | ( | void |  | ) |

Cleanup all module structures, sockets, etc.

This is called at exit. Any registrations and memory allocations need to be unregistered and free'd here. Nothing else will do these for you (until exit).

Returns:
  Zero on success, or non-zero on error.

Definition at line 564 of file app_externalivr.c.

References ast_unregister_application(), and STANDARD_HANGUP_LOCALUSERS.

    00565 {
    00566    int res;
    00567
    00568    res = ast_unregister_application(app);
    00569
    00570    STANDARD_HANGUP_LOCALUSERS;
    00571
    00572    return res;
    00573 }

int usecount | ( | void |  | ) |

Provides a usecount.

This function will be called by various parts of asterisk. Basically, all it has to do is to return a usecount when called. You will need to maintain your usecount within the module somewhere. The usecount should be how many channels provided by this module are in use.

Returns:
  The module's usecount.

Definition at line 585 of file app_externalivr.c.

References STANDARD_USECOUNT.

    00586 {
    00587    int res;
    00588
    00589    STANDARD_USECOUNT(res);
    00590
    00591    return res;
    00592 }

## Variable Documentation

const char* app = "ExternalIVR"`[static]`

Definition at line 52 of file app_externalivr.c.

const char* descrip`[static]`

Definition at line 56 of file app_externalivr.c.

struct ast_generator gen`[static]`

Definition at line 224 of file app_externalivr.c.

Referenced by app_exec().

LOCAL_USER_DECL

Definition at line 84 of file app_externalivr.c.

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

Definition at line 54 of file app_externalivr.c.

const char* tdesc = "External IVR Interface Application"`[static]`

Definition at line 50 of file app_externalivr.c.