Mon Mar 20 08:25:45 2006

Asterisk developer's documentation


Main Page | Modules | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

app.c File Reference

Convenient Application Routines. More...

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <regex.h>
#include "asterisk.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/file.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/logger.h"
#include "asterisk/options.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/indications.h"

Go to the source code of this file.

Data Structures

struct  linear_state

Defines

#define MAX_OTHER_FORMATS   10
#define RES_EXIT   (1 << 17)
#define RES_REPEAT   (1 << 18)
#define RES_RESTART   ((1 << 19) | RES_REPEAT)
#define RES_UPONE   (1 << 16)

Functions

int ast_app_dtget (struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
 Present a dialtone and collect a certain length extension.
int ast_app_getdata (struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
 Plays a stream and gets DTMF data from a channel.
int ast_app_getdata_full (struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
 Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions.
int ast_app_getvoice (struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
int ast_app_group_get_count (char *group, char *category)
int ast_app_group_match_get_count (char *groupmatch, char *category)
int ast_app_group_set_channel (struct ast_channel *chan, char *data)
int ast_app_group_split_group (char *data, char *group, int group_max, char *category, int category_max)
int ast_app_has_voicemail (const char *mailbox, const char *folder)
int ast_app_messagecount (const char *mailbox, int *newmsgs, int *oldmsgs)
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.
unsigned int ast_app_separate_args (char *buf, char delim, char **array, int arraylen)
 Separate a string into arguments in an array.
int ast_control_streamfile (struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms)
int ast_dtmf_stream (struct ast_channel *chan, struct ast_channel *peer, char *digits, int between)
void ast_install_vm_functions (int(*has_voicemail_func)(const char *mailbox, const char *folder), int(*messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs))
int ast_ivr_menu_run (struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
 Runs an IVR menu.
int ast_ivr_menu_run_internal (struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
int ast_linear_stream (struct ast_channel *chan, const char *filename, int fd, int allowoverride)
enum AST_LOCK_RESULT ast_lock_path (const char *path)
 Lock a filesystem path.
int ast_play_and_prepend (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence)
int ast_play_and_record (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
int ast_play_and_wait (struct ast_channel *chan, const char *fn)
char * ast_read_textfile (const char *filename)
int ast_record_review (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
void ast_uninstall_vm_functions (void)
int ast_unlock_path (const char *path)
int ivr_dispatch (struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
void * linear_alloc (struct ast_channel *chan, void *params)
int linear_generator (struct ast_channel *chan, void *data, int len, int samples)
void linear_release (struct ast_channel *chan, void *params)
int option_exists (struct ast_ivr_menu *menu, char *option)
int option_matchmore (struct ast_ivr_menu *menu, char *option)
int read_newoption (struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)

Variables

int(* ast_has_voicemail_func )(const char *mailbox, const char *folder) = NULL
int(* ast_messagecount_func )(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL
int global_maxsilence = 0
int global_silence_threshold = 128
ast_generator linearstream


Detailed Description

Convenient Application Routines.

Definition in file app.c.


Define Documentation

#define MAX_OTHER_FORMATS   10
 

Definition at line 52 of file app.c.

Referenced by ast_play_and_prepend(), and ast_play_and_record().

#define RES_EXIT   (1 << 17)
 

Definition at line 1285 of file app.c.

Referenced by ivr_dispatch().

#define RES_REPEAT   (1 << 18)
 

Definition at line 1286 of file app.c.

Referenced by ivr_dispatch().

#define RES_RESTART   ((1 << 19) | RES_REPEAT)
 

Definition at line 1287 of file app.c.

#define RES_UPONE   (1 << 16)
 

Definition at line 1284 of file app.c.


Function Documentation

int ast_app_dtget struct ast_channel chan,
const char *  context,
char *  collect,
size_t  size,
int  maxlen,
int  timeout
 

Present a dialtone and collect a certain length extension.

Returns:
Returns 1 on valid extension entered, -1 on hangup, or 0 on invalid extension.
Note:
Note that if 'collect' holds digits already, new digits will be appended, so be sure it's initialized properly

Definition at line 62 of file app.c.

References ast_exists_extension(), ast_get_indication_tone(), ast_ignore_pattern(), ast_log(), ast_matchmore_extension(), ast_playtones_start(), ast_playtones_stop(), ast_waitfordigit(), ast_channel::cid, ast_callerid::cid_num, tone_zone_sound::data, ast_pbx::dtimeout, LOG_NOTICE, ast_channel::pbx, and ast_channel::zone.

Referenced by builtin_atxfer(), and builtin_blindtransfer().

00063 {
00064    struct tone_zone_sound *ts;
00065    int res=0, x=0;
00066 
00067    if(maxlen > size)
00068       maxlen = size;
00069    
00070    if(!timeout && chan->pbx)
00071       timeout = chan->pbx->dtimeout;
00072    else if(!timeout)
00073       timeout = 5;
00074    
00075    ts = ast_get_indication_tone(chan->zone,"dial");
00076    if (ts && ts->data[0])
00077       res = ast_playtones_start(chan, 0, ts->data, 0);
00078    else 
00079       ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n");
00080    
00081    for (x = strlen(collect); strlen(collect) < maxlen; ) {
00082       res = ast_waitfordigit(chan, timeout);
00083       if (!ast_ignore_pattern(context, collect))
00084          ast_playtones_stop(chan);
00085       if (res < 1)
00086          break;
00087       collect[x++] = res;
00088       if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num)) {
00089          if (collect[x-1] == '#') {
00090             /* Not a valid extension, ending in #, assume the # was to finish dialing */
00091             collect[x-1] = '\0';
00092          }
00093          break;
00094       }
00095    }
00096    if (res >= 0) {
00097       if (ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num))
00098          res = 1;
00099       else
00100          res = 0;
00101    }
00102    return res;
00103 }

int ast_app_getdata struct ast_channel c,
char *  prompt,
char *  s,
int  maxlen,
int  timeout
 

Plays a stream and gets DTMF data from a channel.

Parameters:
timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for "ludicrous time" (essentially never times out)

Definition at line 109 of file app.c.

References ast_readstring(), ast_streamfile(), ast_pbx::dtimeout, ast_channel::language, ast_channel::pbx, ast_pbx::rtimeout, and s.

Referenced by __login_exec(), auth_exec(), conf_exec(), dictate_exec(), find_conf(), read_exec(), testclient_exec(), testserver_exec(), and vm_exec().

00110 {
00111    int res,to,fto;
00112    /* XXX Merge with full version? XXX */
00113    if (maxlen)
00114       s[0] = '\0';
00115    if (prompt) {
00116       res = ast_streamfile(c, prompt, c->language);
00117       if (res < 0)
00118          return res;
00119    }
00120    fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
00121    to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
00122 
00123    if (timeout > 0) 
00124       fto = to = timeout;
00125    if (timeout < 0) 
00126       fto = to = 1000000000;
00127    res = ast_readstring(c, s, maxlen, to, fto, "#");
00128    return res;
00129 }

int ast_app_getdata_full struct ast_channel c,
char *  prompt,
char *  s,
int  maxlen,
int  timeout,
int  audiofd,
int  ctrlfd
 

Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions.

Definition at line 132 of file app.c.

References ast_readstring_full(), ast_streamfile(), ast_channel::language, and s.

Referenced by handle_getdata().

00133 {
00134    int res,to,fto;
00135    if (prompt) {
00136       res = ast_streamfile(c, prompt, c->language);
00137       if (res < 0)
00138          return res;
00139    }
00140    fto = 6000;
00141    to = 2000;
00142    if (timeout > 0) 
00143       fto = to = timeout;
00144    if (timeout < 0) 
00145       fto = to = 1000000000;
00146    res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
00147    return res;
00148 }

int ast_app_getvoice struct ast_channel c,
char *  dest,
char *  dstfmt,
char *  prompt,
int  silence,
int  maxsec
 

Record voice (after playing prompt if specified), waiting for silence (in ms) up to a given timeout (in s) or '#'

Definition at line 150 of file app.c.

References ast_closestream(), ast_dsp_free(), ast_dsp_new(), ast_dsp_silence(), AST_FORMAT_SLINEAR, ast_frfree(), ast_log(), ast_read(), ast_set_read_format(), ast_streamfile(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), ast_frame::frametype, ast_channel::language, LOG_NOTICE, LOG_WARNING, ast_channel::name, ast_channel::readformat, ast_frame::samples, and ast_frame::subclass.

00151 {
00152    int res;
00153    struct ast_filestream *writer;
00154    int rfmt;
00155    int totalms=0, total;
00156    
00157    struct ast_frame *f;
00158    struct ast_dsp *sildet;
00159    /* Play prompt if requested */
00160    if (prompt) {
00161       res = ast_streamfile(c, prompt, c->language);
00162       if (res < 0)
00163          return res;
00164       res = ast_waitstream(c,"");
00165       if (res < 0)
00166          return res;
00167    }
00168    rfmt = c->readformat;
00169    res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
00170    if (res < 0) {
00171       ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00172       return -1;
00173    }
00174    sildet = ast_dsp_new();
00175    if (!sildet) {
00176       ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00177       return -1;
00178    }
00179    writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
00180    if (!writer) {
00181       ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
00182       ast_dsp_free(sildet);
00183       return -1;
00184    }
00185    for(;;) {
00186       if ((res = ast_waitfor(c, 2000)) < 0) {
00187          ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
00188          break;
00189       }
00190       if (res) {
00191          f = ast_read(c);
00192          if (!f) {
00193             ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
00194             break;
00195          }
00196          if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
00197             /* Ended happily with DTMF */
00198             ast_frfree(f);
00199             break;
00200          } else if (f->frametype == AST_FRAME_VOICE) {
00201             ast_dsp_silence(sildet, f, &total); 
00202             if (total > silence) {
00203                /* Ended happily with silence */
00204                ast_frfree(f);
00205                break;
00206             }
00207             totalms += f->samples / 8;
00208             if (totalms > maxsec * 1000) {
00209                /* Ended happily with too much stuff */
00210                ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
00211                ast_frfree(f);
00212                break;
00213             }
00214             res = ast_writestream(writer, f);
00215             if (res < 0) {
00216                ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
00217                ast_frfree(f);
00218                break;
00219             }
00220                
00221          }
00222          ast_frfree(f);
00223       }
00224    }
00225    res = ast_set_read_format(c, rfmt);
00226    if (res)
00227       ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
00228    ast_dsp_free(sildet);
00229    ast_closestream(writer);
00230    return 0;
00231 }

int ast_app_group_get_count char *  group,
char *  category
 

Get the current channel count of the specified group and category.

Definition at line 1046 of file app.c.

References ast_channel_walk_locked(), ast_mutex_unlock(), ast_strlen_zero(), ast_channel::lock, pbx_builtin_getvar_helper(), and s.

Referenced by group_check_exec(), group_count_exec(), and group_count_function_read().

01047 {
01048    struct ast_channel *chan;
01049    int count = 0;
01050    char *test;
01051    char cat[80];
01052    char *s;
01053 
01054    if (ast_strlen_zero(group))
01055       return 0;
01056 
01057    s = (!ast_strlen_zero(category)) ? category : GROUP_CATEGORY_PREFIX;
01058    ast_copy_string(cat, s, sizeof(cat));
01059 
01060    chan = NULL;
01061    while ((chan = ast_channel_walk_locked(chan)) != NULL) {
01062       test = pbx_builtin_getvar_helper(chan, cat);
01063       if (test && !strcasecmp(test, group))
01064          count++;
01065       ast_mutex_unlock(&chan->lock);
01066    }
01067 
01068    return count;
01069 }

int ast_app_group_match_get_count char *  groupmatch,
char *  category
 

Get the current channel count of all groups that match the specified pattern and category.

Definition at line 1071 of file app.c.

References ast_channel_walk_locked(), ast_mutex_unlock(), ast_strlen_zero(), ast_channel::lock, pbx_builtin_getvar_helper(), and s.

Referenced by group_match_count_exec(), and group_match_count_function_read().

01072 {
01073    regex_t regexbuf;
01074    struct ast_channel *chan;
01075    int count = 0;
01076    char *test;
01077    char cat[80];
01078    char *s;
01079 
01080    if (ast_strlen_zero(groupmatch))
01081       return 0;
01082 
01083    /* if regex compilation fails, return zero matches */
01084    if (regcomp(&regexbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
01085       return 0;
01086 
01087    s = (!ast_strlen_zero(category)) ? category : GROUP_CATEGORY_PREFIX;
01088    ast_copy_string(cat, s, sizeof(cat));
01089 
01090    chan = NULL;
01091    while ((chan = ast_channel_walk_locked(chan)) != NULL) {
01092       test = pbx_builtin_getvar_helper(chan, cat);
01093       if (test && !regexec(&regexbuf, test, 0, NULL, 0))
01094          count++;
01095       ast_mutex_unlock(&chan->lock);
01096    }
01097 
01098    regfree(&regexbuf);
01099 
01100    return count;
01101 }

int ast_app_group_set_channel struct ast_channel chan,
char *  data
 

Set the group for a channel, splitting the provided data into group and category, if specified.

Definition at line 1032 of file app.c.

References ast_app_group_split_group(), and pbx_builtin_setvar_helper().

Referenced by dial_exec_full(), group_function_write(), and group_set_exec().

01033 {
01034    int res=0;
01035    char group[80] = "";
01036    char category[80] = "";
01037 
01038    if (!ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
01039       pbx_builtin_setvar_helper(chan, category, group);
01040    } else
01041       res = -1;
01042 
01043    return res;
01044 }

int ast_app_group_split_group char *  data,
char *  group,
int  group_max,
char *  category,
int  category_max
 

Split a group string into group and category, returning a default category if none is provided.

Definition at line 1003 of file app.c.

References ast_strlen_zero(), and GROUP_CATEGORY_PREFIX.

Referenced by ast_app_group_set_channel(), group_check_exec(), group_count_exec(), group_count_function_read(), group_match_count_exec(), and group_match_count_function_read().

01004 {
01005    int res=0;
01006    char tmp[256];
01007    char *grp=NULL, *cat=NULL;
01008 
01009    if (!ast_strlen_zero(data)) {
01010       ast_copy_string(tmp, data, sizeof(tmp));
01011       grp = tmp;
01012       cat = strchr(tmp, '@');
01013       if (cat) {
01014          *cat = '\0';
01015          cat++;
01016       }
01017    }
01018 
01019    if (!ast_strlen_zero(grp))
01020       ast_copy_string(group, grp, group_max);
01021    else
01022       res = -1;
01023 
01024    if (cat)
01025       snprintf(category, category_max, "%s_%s", GROUP_CATEGORY_PREFIX, cat);
01026    else
01027       ast_copy_string(category, GROUP_CATEGORY_PREFIX, category_max);
01028 
01029    return res;
01030 }

int ast_app_has_voicemail const char *  mailbox,
const char *  folder
 

Determine if a given mailbox has any voicemail

Definition at line 249 of file app.c.

References ast_has_voicemail_func, ast_verbose(), option_verbose, and VERBOSE_PREFIX_3.

Referenced by action_mailboxstatus(), do_monitor(), has_voicemail(), notify_new_message(), play_dialtone(), and update_registry().

00250 {
00251    static int warned = 0;
00252    if (ast_has_voicemail_func)
00253       return ast_has_voicemail_func(mailbox, folder);
00254 
00255    if ((option_verbose > 2) && !warned) {
00256       ast_verbose(VERBOSE_PREFIX_3 "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
00257       warned++;
00258    }
00259    return 0;
00260 }

int ast_app_messagecount const char *  mailbox,
int *  newmsgs,
int *  oldmsgs
 

Determine number of new/old messages in a mailbox

Definition at line 263 of file app.c.

References ast_messagecount_func, ast_verbose(), option_verbose, and VERBOSE_PREFIX_3.

Referenced by action_mailboxcount(), do_housekeeping(), notify_new_message(), sip_send_mwi_to_peer(), and update_registry().

00264 {
00265    static int warned = 0;
00266    if (newmsgs)
00267       *newmsgs = 0;
00268    if (oldmsgs)
00269       *oldmsgs = 0;
00270    if (ast_messagecount_func)
00271       return ast_messagecount_func(mailbox, newmsgs, oldmsgs);
00272 
00273    if (!warned && (option_verbose > 2)) {
00274       warned++;
00275       ast_verbose(VERBOSE_PREFIX_3 "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
00276    }
00277 
00278    return 0;
00279 }

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.

Parameters:
options The array of possible options declared with AST_APP_OPTIONS
flags The flag structure to have option flags set
args The array of argument pointers to hold arguments found
optstr The string containing the options to be parsed
Returns:
zero for success, non-zero if an error occurs
See also:
AST_APP_OPTIONS

Definition at line 1521 of file app.c.

References ast_app_option::arg_index, ast_clear_flag, AST_FLAGS_ALL, ast_log(), ast_set_flag, LOG_WARNING, and s.

Referenced by chanspy_exec(), conf_exec(), dial_exec_full(), mixmonitor_exec(), page_exec(), pbx_builtin_background(), pbx_builtin_resetcdr(), pbx_builtin_waitexten(), vm_exec(), and vm_execmain().

01522 {
01523    char *s;
01524    int curarg;
01525    unsigned int argloc;
01526    char *arg;
01527    int res = 0;
01528 
01529    ast_clear_flag(flags, AST_FLAGS_ALL);
01530 
01531    if (!optstr)
01532       return 0;
01533 
01534    s = optstr;
01535    while (*s) {
01536       curarg = *s++ & 0x7f;
01537       ast_set_flag(flags, options[curarg].flag);
01538       argloc = options[curarg].arg_index;
01539       if (*s == '(') {
01540          /* Has argument */
01541          arg = ++s;
01542          while (*s && (*s != ')'))
01543             s++;
01544          if (*s) {
01545             if (argloc)
01546                args[argloc - 1] = arg;
01547             *s++ = '\0';
01548          } else {
01549             ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
01550             res = -1;
01551          }
01552       } else if (argloc) {
01553          args[argloc - 1] = NULL;
01554       }
01555    }
01556 
01557    return res;
01558 }

unsigned int ast_app_separate_args char *  buf,
char  delim,
char **  array,
int  arraylen
 

Separate a string into arguments in an array.

Parameters:
buf The string to be parsed (this must be a writable copy, as it will be modified)
delim The character to be used to delimit arguments
array An array of 'char *' to be filled in with pointers to the found arguments
arraylen The number of elements in the array (i.e. the number of arguments you will accept)
Note: if there are more arguments in the string than the array will hold, the last element of the array will contain the remaining arguments, not separated.

The array will be completely zeroed by this function before it populates any entries.

Returns:
The number of arguments found, or zero if the function arguments are not valid.

Definition at line 1103 of file app.c.

Referenced by add_agent(), app_exec(), astman_get_variables(), builtin_function_cdr_read(), builtin_function_cdr_write(), builtin_function_checkmd5(), builtin_function_math(), chanspy_exec(), controlplayback_exec(), cut_internal(), dictate_exec(), function_db_exists(), function_db_read(), function_db_write(), pbx_builtin_background(), pbx_builtin_setvar(), pbx_builtin_waitexten(), read_exec(), vm_exec(), and vm_execmain().

01104 {
01105    int argc;
01106    char *scan;
01107    int paren = 0;
01108 
01109    if (!buf || !array || !arraylen)
01110       return 0;
01111 
01112    memset(array, 0, arraylen * sizeof(*array));
01113 
01114    scan = buf;
01115 
01116    for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
01117       array[argc] = scan;
01118       for (; *scan; scan++) {
01119          if (*scan == '(')
01120             paren++;
01121          else if (*scan == ')') {
01122             if (paren)
01123                paren--;
01124          } else if ((*scan == delim) && !paren) {
01125             *scan++ = '\0';
01126             break;
01127          }
01128       }
01129    }
01130 
01131    if (*scan)
01132       array[argc++] = scan;
01133 
01134    return argc;
01135 }

int ast_control_streamfile struct ast_channel chan,
const char *  file,
const char *  fwd,
const char *  rev,
const char *  stop,
const char *  pause,
const char *  restart,
int  skipms
 

Stream a file with fast forward, pause, reverse, restart.

Definition at line 432 of file app.c.

References ast_channel::_state, ast_answer(), ast_log(), ast_seekstream(), ast_stopstream(), ast_streamfile(), ast_tellstream(), ast_waitfordigit(), ast_waitstream_fr(), ast_channel::language, LOG_DEBUG, and ast_channel::stream.

Referenced by controlplayback_exec(), handle_controlstreamfile(), and wait_file().

00436 {
00437    char *breaks = NULL;
00438    char *end = NULL;
00439    int blen = 2;
00440    int res;
00441    long pause_restart_point = 0;
00442 
00443    if (stop)
00444       blen += strlen(stop);
00445    if (pause)
00446       blen += strlen(pause);
00447    if (restart)
00448       blen += strlen(restart);
00449 
00450    if (blen > 2) {
00451       breaks = alloca(blen + 1);
00452       breaks[0] = '\0';
00453       if (stop)
00454          strcat(breaks, stop);
00455       if (pause)
00456          strcat(breaks, pause);
00457       if (restart)
00458          strcat(breaks, restart);
00459    }
00460    if (chan->_state != AST_STATE_UP)
00461       res = ast_answer(chan);
00462 
00463    if (file) {
00464       if ((end = strchr(file,':'))) {
00465          if (!strcasecmp(end, ":end")) {
00466             *end = '\0';
00467             end++;
00468          }
00469       }
00470    }
00471 
00472    for (;;) {
00473       ast_stopstream(chan);
00474       res = ast_streamfile(chan, file, chan->language);
00475       if (!res) {
00476          if (pause_restart_point) {
00477             ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
00478             pause_restart_point = 0;
00479          }
00480          else if (end) {
00481             ast_seekstream(chan->stream, 0, SEEK_END);
00482             end = NULL;
00483          };
00484          res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
00485       }
00486 
00487       if (res < 1)
00488          break;
00489 
00490       /* We go at next loop if we got the restart char */
00491       if (restart && strchr(restart, res)) {
00492          ast_log(LOG_DEBUG, "we'll restart the stream here at next loop\n");
00493          pause_restart_point = 0;
00494          continue;
00495       }
00496 
00497       if (pause && strchr(pause, res)) {
00498          pause_restart_point = ast_tellstream(chan->stream);
00499          for (;;) {
00500             ast_stopstream(chan);
00501             res = ast_waitfordigit(chan, 1000);
00502             if (!res)
00503                continue;
00504             else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
00505                break;
00506          }
00507          if (res == *pause) {
00508             res = 0;
00509             continue;
00510          }
00511       }
00512 
00513       if (res == -1)
00514          break;
00515 
00516       /* if we get one of our stop chars, return it to the calling function */
00517       if (stop && strchr(stop, res))
00518          break;
00519    }
00520 
00521    ast_stopstream(chan);
00522 
00523    return res;
00524 }

int ast_dtmf_stream struct ast_channel chan,
struct ast_channel peer,
char *  digits,
int  between
 

Send DTMF to chan (optionally entertain peer)

Definition at line 281 of file app.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_safe_sleep(), ast_waitfor(), ast_write(), ast_frame::frametype, LOG_WARNING, ast_frame::src, and ast_frame::subclass.

Referenced by ast_bridge_call(), dial_exec_full(), misdn_send_digit(), senddtmf_exec(), testclient_exec(), and testserver_exec().

00282 {
00283    char *ptr;
00284    int res = 0;
00285    struct ast_frame f;
00286    if (!between)
00287       between = 100;
00288 
00289    if (peer)
00290       res = ast_autoservice_start(peer);
00291 
00292    if (!res) {
00293       res = ast_waitfor(chan,100);
00294       if (res > -1) {
00295          for (ptr=digits; *ptr; ptr++) {
00296             if (*ptr == 'w') {
00297                res = ast_safe_sleep(chan, 500);
00298                if (res) 
00299                   break;
00300                continue;
00301             }
00302             memset(&f, 0, sizeof(f));
00303             f.frametype = AST_FRAME_DTMF;
00304             f.subclass = *ptr;
00305             f.src = "ast_dtmf_stream";
00306             if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
00307                ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
00308             } else {
00309                res = ast_write(chan, &f);
00310                if (res) 
00311                   break;
00312                /* pause between digits */
00313                res = ast_safe_sleep(chan,between);
00314                if (res) 
00315                   break;
00316             }
00317          }
00318       }
00319       if (peer) {
00320          /* Stop autoservice on the peer channel, but don't overwrite any error condition 
00321             that has occurred previously while acting on the primary channel */  
00322          if (ast_autoservice_stop(peer) && !res)
00323             res = -1;
00324       }
00325    }
00326    return res;
00327 }

void ast_install_vm_functions int(*)(const char *mailbox, const char *folder)  has_voicemail_func,
int(*)(const char *mailbox, int *newmsgs, int *oldmsgs)  messagecount_func
 

Definition at line 236 of file app.c.

References ast_has_voicemail_func, and ast_messagecount_func.

Referenced by load_module().

00238 {
00239    ast_has_voicemail_func = has_voicemail_func;
00240    ast_messagecount_func = messagecount_func;
00241 }

int ast_ivr_menu_run struct ast_channel c,
struct ast_ivr_menu menu,
void *  cbdata
 

Runs an IVR menu.

Returns:
returns 0 on successful completion, -1 on hangup, or -2 on user error in menu

Definition at line 1478 of file app.c.

References ast_ivr_menu_run_internal().

Referenced by skel_exec().

01479 {
01480    int res;
01481    res = ast_ivr_menu_run_internal(chan, menu, cbdata);
01482    /* Hide internal coding */
01483    if (res > 0)
01484       res = 0;
01485    return res;
01486 }

int ast_ivr_menu_run_internal struct ast_channel chan,
struct ast_ivr_menu menu,
void *  cbdata
[static]
 

Definition at line 1398 of file app.c.

References AST_DIGIT_ANY, ast_log(), ivr_dispatch(), LOG_DEBUG, LOG_WARNING, ast_ivr_option::option, option_exists(), ast_ivr_menu::options, read_newoption(), and ast_ivr_menu::title.

Referenced by ast_ivr_menu_run(), and ivr_dispatch().

01399 {
01400    /* Execute an IVR menu structure */
01401    int res=0;
01402    int pos = 0;
01403    int retries = 0;
01404    char exten[AST_MAX_EXTENSION] = "s";
01405    if (option_exists(menu, "s") < 0) {
01406       strcpy(exten, "g");
01407       if (option_exists(menu, "g") < 0) {
01408          ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
01409          return -1;
01410       }
01411    }
01412    while(!res) {
01413       while(menu->options[pos].option) {
01414          if (!strcasecmp(menu->options[pos].option, exten)) {
01415             res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
01416             ast_log(LOG_DEBUG, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
01417             if (res < 0)
01418                break;
01419             else if (res & RES_UPONE)
01420                return 0;
01421             else if (res & RES_EXIT)
01422                return res;
01423             else if (res & RES_REPEAT) {
01424                int maxretries = res & 0xffff;
01425                if ((res & RES_RESTART) == RES_RESTART) {
01426                   retries = 0;
01427                } else
01428                   retries++;
01429                if (!maxretries)
01430                   maxretries = 3;
01431                if ((maxretries > 0) && (retries >= maxretries)) {
01432                   ast_log(LOG_DEBUG, "Max retries %d exceeded\n", maxretries);
01433                   return -2;
01434                } else {
01435                   if (option_exists(menu, "g") > -1) 
01436                      strcpy(exten, "g");
01437                   else if (option_exists(menu, "s") > -1)
01438                      strcpy(exten, "s");
01439                }
01440                pos=0;
01441                continue;
01442             } else if (res && strchr(AST_DIGIT_ANY, res)) {
01443                ast_log(LOG_DEBUG, "Got start of extension, %c\n", res);
01444                exten[1] = '\0';
01445                exten[0] = res;
01446                if ((res = read_newoption(chan, menu, exten, sizeof(exten))))
01447                   break;
01448                if (option_exists(menu, exten) < 0) {
01449                   if (option_exists(menu, "i")) {
01450                      ast_log(LOG_DEBUG, "Invalid extension entered, going to 'i'!\n");
01451                      strcpy(exten, "i");
01452                      pos = 0;
01453                      continue;
01454                   } else {
01455                      ast_log(LOG_DEBUG, "Aborting on invalid entry, with no 'i' option!\n");
01456                      res = -2;
01457                      break;
01458                   }
01459                } else {
01460                   ast_log(LOG_DEBUG, "New existing extension: %s\n", exten);
01461                   pos = 0;
01462                   continue;
01463                }
01464             }
01465          }
01466          pos++;
01467       }
01468       ast_log(LOG_DEBUG, "Stopping option '%s', res is %d\n", exten, res);
01469       pos = 0;
01470       if (!strcasecmp(exten, "s"))
01471          strcpy(exten, "g");
01472       else
01473          break;
01474    }
01475    return res;
01476 }

int ast_linear_stream struct ast_channel chan,
const char *  filename,
int  fd,
int  allowoverride
 

Stream a filename (or file descriptor) as a generator.

Definition at line 401 of file app.c.

References linear_state::allowoverride, ast_activate_generator(), ast_config_AST_VAR_DIR, ast_log(), ast_strlen_zero(), linear_state::autoclose, linear_state::fd, linearstream, LOG_WARNING, and malloc.

00402 {
00403    struct linear_state *lin;
00404    char tmpf[256];
00405    int res = -1;
00406    int autoclose = 0;
00407    if (fd < 0) {
00408       if (ast_strlen_zero(filename))
00409          return -1;
00410       autoclose = 1;
00411       if (filename[0] == '/') 
00412          ast_copy_string(tmpf, filename, sizeof(tmpf));
00413       else
00414          snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename);
00415       fd = open(tmpf, O_RDONLY);
00416       if (fd < 0){
00417          ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
00418          return -1;
00419       }
00420    }
00421    lin = malloc(sizeof(struct linear_state));
00422    if (lin) {
00423       memset(lin, 0, sizeof(lin));
00424       lin->fd = fd;
00425       lin->allowoverride = allowoverride;
00426       lin->autoclose = autoclose;
00427       res = ast_activate_generator(chan, &linearstream, lin);
00428    }
00429    return res;
00430 }

enum AST_LOCK_RESULT ast_lock_path const char *  path  ) 
 

Lock a filesystem path.

Parameters:
path the path to be locked
Returns:
one of AST_LOCK_RESULT values

Definition at line 1137 of file app.c.

References AST_LOCK_RESULT, ast_log(), LOG_DEBUG, LOG_WARNING, and s.

Referenced by vm_lock_path().

01138 {
01139    char *s;
01140    char *fs;
01141    int res;
01142    int fd;
01143    time_t start;
01144 
01145    s = alloca(strlen(path) + 10);
01146    fs = alloca(strlen(path) + 20);
01147 
01148    if (!fs || !s) {
01149       ast_log(LOG_WARNING, "Out of memory!\n");
01150       return AST_LOCK_FAILURE;
01151    }
01152 
01153    snprintf(fs, strlen(path) + 19, "%s/.lock-%08x", path, rand());
01154    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
01155    if (fd < 0) {
01156       fprintf(stderr, "Unable to create lock file '%s': %s\n", path, strerror(errno));
01157       return AST_LOCK_PATH_NOT_FOUND;
01158    }
01159    close(fd);
01160 
01161    snprintf(s, strlen(path) + 9, "%s/.lock", path);
01162    time(&start);
01163    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
01164       usleep(1);
01165    if (res) {
01166       ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
01167       return AST_LOCK_TIMEOUT;
01168    } else {
01169       unlink(fs);
01170       ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
01171       return AST_LOCK_SUCCESS;
01172    }
01173 }

int ast_play_and_prepend struct ast_channel chan,
char *  playfile,
char *  recordfile,
int  maxtime_sec,
char *  fmt,
int *  duration,
int  beep,
int  silencethreshold,
int  maxsilence_ms
 

Record a message and prepend the message to the given record file after playing the optional playfile (or a beep), storing the duration in 'duration' and with a maximum
permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults.

Definition at line 766 of file app.c.

References ast_closestream(), ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), ast_filedelete(), ast_filerename(), AST_FORMAT_SLINEAR, ast_frfree(), ast_getformatname(), ast_log(), ast_play_and_wait(), ast_read(), ast_readfile(), ast_readframe(), ast_set_read_format(), ast_strdupa, ast_stream_rewind(), ast_streamfile(), ast_truncstream(), ast_verbose(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), fmt, ast_frame::frametype, ast_channel::language, LOG_DEBUG, LOG_WARNING, MAX_OTHER_FORMATS, ast_channel::name, option_verbose, ast_channel::readformat, strsep(), ast_frame::subclass, and VERBOSE_PREFIX_3.

Referenced by vm_forwardoptions().

00767 {
00768    int d = 0;
00769    char *fmts;
00770    char comment[256];
00771    int x, fmtcnt=1, res=-1,outmsg=0;
00772    struct ast_frame *f;
00773    struct ast_filestream *others[MAX_OTHER_FORMATS];
00774    struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
00775    char *sfmt[MAX_OTHER_FORMATS];
00776    char *stringp=NULL;
00777    time_t start, end;
00778    struct ast_dsp *sildet;    /* silence detector dsp */
00779    int totalsilence = 0;
00780    int dspsilence = 0;
00781    int gotsilence = 0;     /* did we timeout for silence? */
00782    int rfmt=0; 
00783    char prependfile[80];
00784    
00785    if (silencethreshold < 0)
00786       silencethreshold = global_silence_threshold;
00787 
00788    if (maxsilence < 0)
00789       maxsilence = global_maxsilence;
00790 
00791    /* barf if no pointer passed to store duration in */
00792    if (duration == NULL) {
00793       ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
00794       return -1;
00795    }
00796 
00797    ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00798    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00799 
00800    if (playfile || beep) { 
00801       if (!beep)
00802          d = ast_play_and_wait(chan, playfile);
00803       if (d > -1)
00804          d = ast_streamfile(chan, "beep",chan->language);
00805       if (!d)
00806          d = ast_waitstream(chan,"");
00807       if (d < 0)
00808          return -1;
00809    }
00810    ast_copy_string(prependfile, recordfile, sizeof(prependfile)); 
00811    strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00812          
00813    fmts = ast_strdupa(fmt);
00814    
00815    stringp=fmts;
00816    strsep(&stringp, "|");
00817    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);   
00818    sfmt[0] = ast_strdupa(fmts);
00819    
00820    while((fmt = strsep(&stringp, "|"))) {
00821       if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00822          ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
00823          break;
00824       }
00825       sfmt[fmtcnt++] = ast_strdupa(fmt);
00826    }
00827 
00828    time(&start);
00829    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
00830    for (x=0;x<fmtcnt;x++) {
00831       others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00832       ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing:  %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
00833       if (!others[x]) {
00834          break;
00835       }
00836    }
00837    
00838    sildet = ast_dsp_new(); /* Create the silence detector */
00839    if (!sildet) {
00840       ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00841       return -1;
00842    }
00843    ast_dsp_set_threshold(sildet, silencethreshold);
00844 
00845    if (maxsilence > 0) {
00846       rfmt = chan->readformat;
00847       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00848       if (res < 0) {
00849          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00850          ast_dsp_free(sildet);
00851          return -1;
00852       }
00853    }
00854                   
00855    if (x == fmtcnt) {
00856    /* Loop forever, writing the packets we read to the writer(s), until
00857       we read a # or get a hangup */
00858       f = NULL;
00859       for(;;) {
00860          res = ast_waitfor(chan, 2000);
00861          if (!res) {
00862             ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00863             /* Try one more time in case of masq */
00864             res = ast_waitfor(chan, 2000);
00865             if (!res) {
00866                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00867                res = -1;
00868             }
00869          }
00870          
00871          if (res < 0) {
00872             f = NULL;
00873             break;
00874          }
00875          f = ast_read(chan);
00876          if (!f)
00877             break;
00878          if (f->frametype == AST_FRAME_VOICE) {
00879             /* write each format */
00880             for (x=0;x<fmtcnt;x++) {
00881                if (!others[x])
00882                   break;
00883                res = ast_writestream(others[x], f);
00884             }
00885             
00886             /* Silence Detection */
00887             if (maxsilence > 0) {
00888                dspsilence = 0;
00889                ast_dsp_silence(sildet, f, &dspsilence);
00890                if (dspsilence)
00891                   totalsilence = dspsilence;
00892                else
00893                   totalsilence = 0;
00894                
00895                if (totalsilence > maxsilence) {
00896                /* Ended happily with silence */
00897                if (option_verbose > 2) 
00898                   ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00899                ast_frfree(f);
00900                gotsilence = 1;
00901                outmsg=2;
00902                break;
00903                }
00904             }
00905             /* Exit on any error */
00906             if (res) {
00907                ast_log(LOG_WARNING, "Error writing frame\n");
00908                ast_frfree(f);
00909                break;
00910             }
00911          } else if (f->frametype == AST_FRAME_VIDEO) {
00912             /* Write only once */
00913             ast_writestream(others[0], f);
00914          } else if (f->frametype == AST_FRAME_DTMF) {
00915             /* stop recording with any digit */
00916             if (option_verbose > 2) 
00917                ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00918             res = 't';
00919             outmsg = 2;
00920             ast_frfree(f);
00921             break;
00922          }
00923          if (maxtime) {
00924             time(&end);
00925             if (maxtime < (end - start)) {
00926                if (option_verbose > 2)
00927                   ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00928                res = 't';
00929                outmsg=2;
00930                ast_frfree(f);
00931                break;
00932             }
00933          }
00934          ast_frfree(f);
00935       }
00936       if (end == start) time(&end);
00937       if (!f) {
00938          if (option_verbose > 2) 
00939             ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00940          res = -1;
00941          outmsg=1;
00942 #if 0
00943          /* delete all the prepend files */
00944          for (x=0;x<fmtcnt;x++) {
00945             if (!others[x])
00946                break;
00947             ast_closestream(others[x]);
00948             ast_filedelete(prependfile, sfmt[x]);
00949          }
00950 #endif
00951       }
00952    } else {
00953       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]); 
00954    }
00955    ast_dsp_free(sildet);
00956    *duration = end - start;
00957 #if 0
00958    if (outmsg > 1) {
00959 #else
00960    if (outmsg) {
00961 #endif
00962       struct ast_frame *fr;
00963       for (x=0;x<fmtcnt;x++) {
00964          snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
00965          realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00966          if (!others[x] || !realfiles[x])
00967             break;
00968          if (totalsilence)
00969             ast_stream_rewind(others[x], totalsilence-200);
00970          else
00971             ast_stream_rewind(others[x], 200);
00972          ast_truncstream(others[x]);
00973          /* add the original file too */
00974          while ((fr = ast_readframe(realfiles[x]))) {
00975             ast_writestream(others[x],fr);
00976          }
00977          ast_closestream(others[x]);
00978          ast_closestream(realfiles[x]);
00979          ast_filerename(prependfile, recordfile, sfmt[x]);
00980 #if 0
00981          ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
00982 #endif
00983          ast_filedelete(prependfile, sfmt[x]);
00984       }
00985    }
00986    if (rfmt) {
00987       if (ast_set_read_format(chan, rfmt)) {
00988          ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00989       }
00990    }
00991    if (outmsg) {
00992       if (outmsg > 1) {
00993          /* Let them know it worked */
00994          ast_streamfile(chan, "auth-thankyou", chan->language);
00995          ast_waitstream(chan, "");
00996       }
00997    }  
00998    return res;
00999 }

int ast_play_and_record struct ast_channel chan,
const char *  playfile,
const char *  recordfile,
int  maxtime_sec,
const char *  fmt,
int *  duration,
int  silencethreshold,
int  maxsilence_ms,
const char *  path
 

Record a file for a max amount of time (in seconds), in a given list of formats separated by '|', outputting the duration of the recording, and with a maximum
permitted silence time in milliseconds of 'maxsilence' under 'silencethreshold' or use '-1' for either or both parameters for defaults. calls ast_unlock_path() on 'path' if passed

Definition at line 540 of file app.c.

References ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_closestream(), AST_CONTROL_VIDUPDATE, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FORMAT_SLINEAR, ast_frfree(), ast_getformatname(), ast_indicate(), ast_log(), ast_play_and_wait(), ast_read(), ast_set_read_format(), ast_strdupa, ast_stream_rewind(), ast_streamfile(), ast_truncstream(), ast_unlock_path(), ast_verbose(), ast_waitfor(), ast_waitstream(), ast_writefile(), ast_writestream(), fmt, ast_frame::frametype, ast_channel::language, LOG_DEBUG, LOG_WARNING, MAX_OTHER_FORMATS, ast_channel::name, option_verbose, ast_channel::readformat, strsep(), ast_frame::subclass, and VERBOSE_PREFIX_3.

Referenced by ast_record_review(), dial_exec_full(), and play_record_review().

00541 {
00542    int d;
00543    char *fmts;
00544    char comment[256];
00545    int x, fmtcnt=1, res=-1,outmsg=0;
00546    struct ast_frame *f;
00547    struct ast_filestream *others[MAX_OTHER_FORMATS];
00548    char *sfmt[MAX_OTHER_FORMATS];
00549    char *stringp=NULL;
00550    time_t start, end;
00551    struct ast_dsp *sildet=NULL;     /* silence detector dsp */
00552    int totalsilence = 0;
00553    int dspsilence = 0;
00554    int gotsilence = 0;     /* did we timeout for silence? */
00555    int rfmt=0;
00556    struct ast_silence_generator *silgen = NULL;
00557 
00558    if (silencethreshold < 0)
00559       silencethreshold = global_silence_threshold;
00560 
00561    if (maxsilence < 0)
00562       maxsilence = global_maxsilence;
00563 
00564    /* barf if no pointer passed to store duration in */
00565    if (duration == NULL) {
00566       ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00567       return -1;
00568    }
00569 
00570    ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00571    snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00572 
00573    if (playfile) {
00574       d = ast_play_and_wait(chan, playfile);
00575       if (d > -1)
00576          d = ast_streamfile(chan, "beep",chan->language);
00577       if (!d)
00578          d = ast_waitstream(chan,"");
00579       if (d < 0)
00580          return -1;
00581    }
00582 
00583    fmts = ast_strdupa(fmt);
00584 
00585    stringp=fmts;
00586    strsep(&stringp, "|");
00587    ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00588    sfmt[0] = ast_strdupa(fmts);
00589 
00590    while((fmt = strsep(&stringp, "|"))) {
00591       if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00592          ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
00593          break;
00594       }
00595       sfmt[fmtcnt++] = ast_strdupa(fmt);
00596    }
00597 
00598    time(&start);
00599    end=start;  /* pre-initialize end to be same as start in case we never get into loop */
00600    for (x=0;x<fmtcnt;x++) {
00601       others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00602       ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing:  %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
00603 
00604       if (!others[x]) {
00605          break;
00606       }
00607    }
00608 
00609    if (path)
00610       ast_unlock_path(path);
00611 
00612    if (maxsilence > 0) {
00613       sildet = ast_dsp_new(); /* Create the silence detector */
00614       if (!sildet) {
00615          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00616          return -1;
00617       }
00618       ast_dsp_set_threshold(sildet, silencethreshold);
00619       rfmt = chan->readformat;
00620       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00621       if (res < 0) {
00622          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00623          ast_dsp_free(sildet);
00624          return -1;
00625       }
00626    }
00627 
00628    /* Request a video update */
00629    ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00630 
00631    if (option_transmit_silence_during_record)
00632       silgen = ast_channel_start_silence_generator(chan);
00633 
00634    if (x == fmtcnt) {
00635    /* Loop forever, writing the packets we read to the writer(s), until
00636       we read a # or get a hangup */
00637       f = NULL;
00638       for(;;) {
00639          res = ast_waitfor(chan, 2000);
00640          if (!res) {
00641             ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00642             /* Try one more time in case of masq */
00643             res = ast_waitfor(chan, 2000);
00644             if (!res) {
00645                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00646                res = -1;
00647             }
00648          }
00649 
00650          if (res < 0) {
00651             f = NULL;
00652             break;
00653          }
00654          f = ast_read(chan);
00655          if (!f)
00656             break;
00657          if (f->frametype == AST_FRAME_VOICE) {
00658             /* write each format */
00659             for (x=0;x<fmtcnt;x++) {
00660                res = ast_writestream(others[x], f);
00661             }
00662 
00663             /* Silence Detection */
00664             if (maxsilence > 0) {
00665                dspsilence = 0;
00666                ast_dsp_silence(sildet, f, &dspsilence);
00667                if (dspsilence)
00668                   totalsilence = dspsilence;
00669                else
00670                   totalsilence = 0;
00671 
00672                if (totalsilence > maxsilence) {
00673                   /* Ended happily with silence */
00674                   if (option_verbose > 2)
00675                      ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00676                   ast_frfree(f);
00677                   gotsilence = 1;
00678                   outmsg=2;
00679                   break;
00680                }
00681             }
00682             /* Exit on any error */
00683             if (res) {
00684                ast_log(LOG_WARNING, "Error writing frame\n");
00685                ast_frfree(f);
00686                break;
00687             }
00688          } else if (f->frametype == AST_FRAME_VIDEO) {
00689             /* Write only once */
00690             ast_writestream(others[0], f);
00691          } else if (f->frametype == AST_FRAME_DTMF) {
00692             if (f->subclass == '#') {
00693                if (option_verbose > 2)
00694                   ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00695                res = '#';
00696                outmsg = 2;
00697                ast_frfree(f);
00698                break;
00699             }
00700             if (f->subclass == '0') {
00701             /* Check for a '0' during message recording also, in case caller wants operator */
00702                if (option_verbose > 2)
00703                   ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
00704                res = '0';
00705                outmsg = 0;
00706                ast_frfree(f);
00707                break;
00708             }
00709          }
00710          if (maxtime) {
00711             time(&end);
00712             if (maxtime < (end - start)) {
00713                if (option_verbose > 2)
00714                   ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00715                outmsg = 2;
00716                res = 't';
00717                ast_frfree(f);
00718                break;
00719             }
00720          }
00721          ast_frfree(f);
00722       }
00723       if (end == start) time(&end);
00724       if (!f) {
00725          if (option_verbose > 2)
00726             ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00727          res = -1;
00728          outmsg=1;
00729       }
00730    } else {
00731       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00732    }
00733 
00734    if (silgen)
00735       ast_channel_stop_silence_generator(chan, silgen);
00736 
00737    *duration = end - start;
00738 
00739    for (x=0;x<fmtcnt;x++) {
00740       if (!others[x])
00741          break;
00742       if (res > 0) {
00743          if (totalsilence)
00744             ast_stream_rewind(others[x], totalsilence-200);
00745          else
00746             ast_stream_rewind(others[x], 200);
00747       }
00748       ast_truncstream(others[x]);
00749       ast_closestream(others[x]);
00750    }
00751    if (rfmt) {
00752       if (ast_set_read_format(chan, rfmt)) {
00753          ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00754       }
00755    }
00756    if (outmsg > 1) {
00757       /* Let them know recording is stopped */
00758       if(!ast_streamfile(chan, "auth-thankyou", chan->language))
00759          ast_waitstream(chan, "");
00760    }
00761    if (sildet)
00762       ast_dsp_free(sildet);
00763    return res;
00764 }

int ast_play_and_wait struct ast_channel chan,
const char *  fn
 

Play a stream and wait for a digit, returning the digit that was pressed

Definition at line 526 of file app.c.

References AST_DIGIT_ANY, ast_stopstream(), ast_streamfile(), ast_waitstream(), and ast_channel::language.

Referenced by advanced_options(), ast_play_and_prepend(), ast_play_and_record(), ast_record_review(), dial_exec_full(), dialout(), forward_message(), get_folder(), get_folder2(), leave_voicemail(), play_message_category(), play_record_review(), vm_authenticate(), vm_browse_messages_en(), vm_browse_messages_es(), vm_browse_messages_gr(), vm_browse_messages_it(), vm_browse_messages_pt(), vm_execmain(), vm_forwardoptions(), vm_instructions(), vm_intro_cz(), vm_intro_de(), vm_intro_en(), vm_intro_es(), vm_intro_fr(), vm_intro_gr(), vm_intro_it(), vm_intro_nl(), vm_intro_no(), vm_intro_pt(), vm_intro_se(), vm_newuser(), vm_options(), vm_play_folder_name(), vm_play_folder_name_gr(), vm_tempgreeting(), and vmauthenticate().

00527 {
00528    int d;
00529    d = ast_streamfile(chan, fn, chan->language);
00530    if (d)
00531       return d;
00532    d = ast_waitstream(chan, AST_DIGIT_ANY);
00533    ast_stopstream(chan);
00534    return d;
00535 }

char* ast_read_textfile const char *  file  ) 
 

Read a file into asterisk

Definition at line 1488 of file app.c.

References ast_log(), free, LOG_WARNING, and malloc.

Referenced by readfile_exec().

01489 {
01490    int fd;
01491    char *output=NULL;
01492    struct stat filesize;
01493    int count=0;
01494    int res;
01495    if(stat(filename,&filesize)== -1){
01496       ast_log(LOG_WARNING,"Error can't stat %s\n", filename);
01497       return NULL;
01498    }
01499    count=filesize.st_size + 1;
01500    fd = open(filename, O_RDONLY);
01501    if (fd < 0) {
01502       ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
01503       return NULL;
01504    }
01505    output=(char *)malloc(count);
01506    if (output) {
01507       res = read(fd, output, count - 1);
01508       if (res == count - 1) {
01509          output[res] = '\0';
01510       } else {
01511          ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count -  1, strerror(errno));
01512          free(output);
01513          output = NULL;
01514       }
01515    } else 
01516       ast_log(LOG_WARNING, "Out of memory!\n");
01517    close(fd);
01518    return output;
01519 }

int ast_record_review struct ast_channel chan,
const char *  playfile,
const char *  recordfile,
int  maxtime,
const char *  fmt,
int *  duration,
const char *  path
 

Allow to record message and have a review option

Definition at line 1186 of file app.c.

References AST_DIGIT_ANY, ast_log(), ast_play_and_record(), ast_play_and_wait(), ast_streamfile(), ast_verbose(), ast_waitfordigit(), ast_waitstream(), fmt, ast_channel::language, LOG_WARNING, and VERBOSE_PREFIX_3.

Referenced by conf_run().

01187 {
01188    int silencethreshold = 128; 
01189    int maxsilence=0;
01190    int res = 0;
01191    int cmd = 0;
01192    int max_attempts = 3;
01193    int attempts = 0;
01194    int recorded = 0;
01195    int message_exists = 0;
01196    /* Note that urgent and private are for flagging messages as such in the future */
01197 
01198    /* barf if no pointer passed to store duration in */
01199    if (duration == NULL) {
01200       ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
01201       return -1;
01202    }
01203 
01204    cmd = '3';   /* Want to start by recording */
01205 
01206    while ((cmd >= 0) && (cmd != 't')) {
01207       switch (cmd) {
01208       case '1':
01209          if (!message_exists) {
01210             /* In this case, 1 is to record a message */
01211             cmd = '3';
01212             break;
01213          } else {
01214             ast_streamfile(chan, "vm-msgsaved", chan->language);
01215             ast_waitstream(chan, "");
01216             cmd = 't';
01217             return res;
01218          }
01219       case '2':
01220          /* Review */
01221          ast_verbose(VERBOSE_PREFIX_3 "Reviewing the recording\n");
01222          ast_streamfile(chan, recordfile, chan->language);
01223          cmd = ast_waitstream(chan, AST_DIGIT_ANY);
01224          break;
01225       case '3':
01226          message_exists = 0;
01227          /* Record */
01228          if (recorded == 1)
01229             ast_verbose(VERBOSE_PREFIX_3 "Re-recording\n");
01230          else  
01231             ast_verbose(VERBOSE_PREFIX_3 "Recording\n");
01232          recorded = 1;
01233          cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path);
01234          if (cmd == -1) {
01235          /* User has hung up, no options to give */
01236             return cmd;
01237          }
01238          if (cmd == '0') {
01239             break;
01240          } else if (cmd == '*') {
01241             break;
01242          } 
01243          else {
01244             /* If all is well, a message exists */
01245             message_exists = 1;
01246             cmd = 0;
01247          }
01248          break;
01249       case '4':
01250       case '5':
01251       case '6':
01252       case '7':
01253       case '8':
01254       case '9':
01255       case '*':
01256       case '#':
01257          cmd = ast_play_and_wait(chan, "vm-sorry");
01258          break;
01259       default:
01260          if (message_exists) {
01261             cmd = ast_play_and_wait(chan, "vm-review");
01262          }
01263          else {
01264             cmd = ast_play_and_wait(chan, "vm-torerecord");
01265             if (!cmd)
01266                cmd = ast_waitfordigit(chan, 600);
01267          }
01268          
01269          if (!cmd)
01270             cmd = ast_waitfordigit(chan, 6000);
01271          if (!cmd) {
01272             attempts++;
01273          }
01274          if (attempts > max_attempts) {
01275             cmd = 't';
01276          }
01277       }
01278    }
01279    if (cmd == 't')
01280       cmd = 0;
01281    return cmd;
01282 }

void ast_uninstall_vm_functions void   ) 
 

Definition at line 243 of file app.c.

References ast_has_voicemail_func, and ast_messagecount_func.

Referenced by unload_module().

00244 {
00245    ast_has_voicemail_func = NULL;
00246    ast_messagecount_func = NULL;
00247 }

int ast_unlock_path const char *  path  ) 
 

Unlock a path

Definition at line 1175 of file app.c.

References ast_log(), LOG_DEBUG, and s.

Referenced by ast_play_and_record(), close_mailbox(), copy_message(), count_messages(), last_message_index(), leave_voicemail(), resequence_mailbox(), and save_to_folder().

01176 {
01177    char *s;
01178    s = alloca(strlen(path) + 10);
01179    if (!s)
01180       return -1;
01181    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01182    ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01183    return unlink(s);
01184 }

int ivr_dispatch struct ast_channel chan,
struct ast_ivr_option option,
char *  exten,
void *  cbdata
[static]
 

Definition at line 1290 of file app.c.

References ast_ivr_option::action, ast_ivr_option::adata, AST_ACTION_BACKGROUND, AST_ACTION_BACKLIST, AST_ACTION_CALLBACK, AST_ACTION_EXIT, AST_ACTION_MENU, AST_ACTION_NOOP, AST_ACTION_PLAYBACK, AST_ACTION_PLAYLIST, AST_ACTION_REPEAT, AST_ACTION_RESTART, AST_ACTION_TRANSFER, AST_ACTION_UPONE, AST_ACTION_WAITOPTION, AST_DIGIT_ANY, ast_ivr_menu_run_internal(), ast_log(), ast_parseable_goto(), ast_stopstream(), ast_strdupa, ast_streamfile(), ast_waitfordigit(), ast_waitstream(), ast_channel::language, LOG_NOTICE, ast_channel::pbx, RES_EXIT, RES_REPEAT, ast_pbx::rtimeout, and strsep().

Referenced by ast_ivr_menu_run_internal().

01291 {
01292    int res;
01293    int (*ivr_func)(struct ast_channel *, void *);
01294    char *c;
01295    char *n;
01296    
01297    switch(option->action) {
01298    case AST_ACTION_UPONE:
01299       return RES_UPONE;
01300    case AST_ACTION_EXIT:
01301       return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
01302    case AST_ACTION_REPEAT:
01303       return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
01304    case AST_ACTION_RESTART:
01305       return RES_RESTART ;
01306    case AST_ACTION_NOOP:
01307       return 0;
01308    case AST_ACTION_BACKGROUND:
01309       res = ast_streamfile(chan, (char *)option->adata, chan->language);
01310       if (!res) {
01311          res = ast_waitstream(chan, AST_DIGIT_ANY);
01312       } else {
01313          ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01314          res = 0;
01315       }
01316       return res;
01317    case AST_ACTION_PLAYBACK:
01318       res = ast_streamfile(chan, (char *)option->adata, chan->language);
01319       if (!res) {
01320          res = ast_waitstream(chan, "");
01321       } else {
01322          ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01323          res = 0;
01324       }
01325       return res;
01326    case AST_ACTION_MENU:
01327       res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata);
01328       /* Do not pass entry errors back up, treaat ast though ti was an "UPONE" */
01329       if (res == -2)
01330          res = 0;
01331       return res;
01332    case AST_ACTION_WAITOPTION:
01333       res = ast_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10));
01334       if (!res)
01335          return 't';
01336       return res;
01337    case AST_ACTION_CALLBACK:
01338       ivr_func = option->adata;
01339       res = ivr_func(chan, cbdata);
01340       return res;
01341    case AST_ACTION_TRANSFER:
01342       res = ast_parseable_goto(chan, option->adata);
01343       return 0;
01344    case AST_ACTION_PLAYLIST:
01345    case AST_ACTION_BACKLIST:
01346       res = 0;
01347       c = ast_strdupa(option->adata);
01348       if (c) {
01349          while((n = strsep(&c, ";")))
01350             if ((res = ast_streamfile(chan, n, chan->language)) || (res = ast_waitstream(chan, (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
01351                break;
01352          ast_stopstream(chan);
01353       }
01354       return res;
01355    default:
01356       ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
01357       return 0;
01358    };
01359    return -1;
01360 }

void* linear_alloc struct ast_channel chan,
void *  params
[static]
 

Definition at line 374 of file app.c.

References linear_state::allowoverride, ast_clear_flag, AST_FLAG_WRITE_INT, AST_FORMAT_SLINEAR, ast_log(), ast_set_flag, ast_set_write_format(), free, LOG_WARNING, ast_channel::name, linear_state::origwfmt, and ast_channel::writeformat.

00375 {
00376    struct linear_state *ls;
00377    /* In this case, params is already malloc'd */
00378    if (params) {
00379       ls = params;
00380       if (ls->allowoverride)
00381          ast_set_flag(chan, AST_FLAG_WRITE_INT);
00382       else
00383          ast_clear_flag(chan, AST_FLAG_WRITE_INT);
00384       ls->origwfmt = chan->writeformat;
00385       if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00386          ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
00387          free(ls);
00388          ls = params = NULL;
00389       }
00390    }
00391    return params;
00392 }

int linear_generator struct ast_channel chan,
void *  data,
int  len,
int  samples
[static]
 

Definition at line 347 of file app.c.

References AST_FRIENDLY_OFFSET, ast_log(), ast_write(), ast_frame::data, ast_frame::datalen, linear_state::fd, ast_frame::frametype, LOG_WARNING, ast_frame::offset, ast_frame::samples, and ast_frame::subclass.

00348 {
00349    struct ast_frame f;
00350    short buf[2048 + AST_FRIENDLY_OFFSET / 2];
00351    struct linear_state *ls = data;
00352    int res;
00353    len = samples * 2;
00354    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00355       ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
00356       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00357    }
00358    memset(&f, 0, sizeof(f));
00359    res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
00360    if (res > 0) {
00361       f.frametype = AST_FRAME_VOICE;
00362       f.subclass = AST_FORMAT_SLINEAR;
00363       f.data = buf + AST_FRIENDLY_OFFSET/2;
00364       f.datalen = res;
00365       f.samples = res / 2;
00366       f.offset = AST_FRIENDLY_OFFSET;
00367       ast_write(chan, &f);
00368       if (res == len)
00369          return 0;
00370    }
00371    return -1;
00372 }

void linear_release struct ast_channel chan,
void *  params
[static]
 

Definition at line 336 of file app.c.

References ast_log(), ast_set_write_format(), linear_state::autoclose, linear_state::fd, free, LOG_WARNING, ast_channel::name, and linear_state::origwfmt.

00337 {
00338    struct linear_state *ls = params;
00339    if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
00340       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
00341    }
00342    if (ls->autoclose)
00343       close(ls->fd);
00344    free(params);
00345 }

int option_exists struct ast_ivr_menu menu,
char *  option
[static]
 

Definition at line 1362 of file app.c.

References ast_ivr_option::option, and ast_ivr_menu::options.

Referenced by ast_ivr_menu_run_internal().

01363 {
01364    int x;
01365    for (x=0;menu->options[x].option;x++)
01366       if (!strcasecmp(menu->options[x].option, option))
01367          return x;
01368    return -1;
01369 }

int option_matchmore struct ast_ivr_menu menu,
char *  option
[static]
 

Definition at line 1371 of file app.c.

References ast_ivr_option::option, and ast_ivr_menu::options.

Referenced by read_newoption().

01372 {
01373    int x;
01374    for (x=0;menu->options[x].option;x++)
01375       if ((!strncasecmp(menu->options[x].option, option, strlen(option))) && 
01376             (menu->options[x].option[strlen(option)]))
01377          return x;
01378    return -1;
01379 }

int read_newoption struct ast_channel chan,
struct ast_ivr_menu menu,
char *  exten,
int  maxexten
[static]
 

Definition at line 1381 of file app.c.

References ast_waitfordigit(), ast_pbx::dtimeout, option_matchmore(), and ast_channel::pbx.

Referenced by ast_ivr_menu_run_internal().

01382 {
01383    int res=0;
01384    int ms;
01385    while(option_matchmore(menu, exten)) {
01386       ms = chan->pbx ? chan->pbx->dtimeout : 5000;
01387       if (strlen(exten) >= maxexten - 1) 
01388          break;
01389       res = ast_waitfordigit(chan, ms);
01390       if (res < 1)
01391          break;
01392       exten[strlen(exten) + 1] = '\0';
01393       exten[strlen(exten)] = res;
01394    }
01395    return res > 0 ? 0 : res;
01396 }


Variable Documentation

int(* ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL [static]
 

Definition at line 233 of file app.c.

Referenced by ast_app_has_voicemail(), ast_install_vm_functions(), and ast_uninstall_vm_functions().

int(* ast_messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL [static]
 

Definition at line 234 of file app.c.

Referenced by ast_app_messagecount(), ast_install_vm_functions(), and ast_uninstall_vm_functions().

int global_maxsilence = 0 [static]
 

Definition at line 538 of file app.c.

int global_silence_threshold = 128 [static]
 

Definition at line 537 of file app.c.

struct ast_generator linearstream [static]
 

Definition at line 394 of file app.c.

Referenced by ast_linear_stream().


Generated on Mon Mar 20 08:25:45 2006 for Asterisk - the Open Source PBX by  doxygen 1.3.9.1