Mon Mar 19 11:30:31 2012

Asterisk developer's documentation


app.c File Reference

Convenient Application Routines. More...

#include "asterisk.h"
#include <sys/stat.h>
#include <regex.h>
#include <sys/file.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <dirent.h>
#include <sys/capability.h>
#include "asterisk/paths.h"
#include "asterisk/channel.h"
#include "asterisk/pbx.h"
#include "asterisk/file.h"
#include "asterisk/app.h"
#include "asterisk/dsp.h"
#include "asterisk/utils.h"
#include "asterisk/lock.h"
#include "asterisk/indications.h"
#include "asterisk/linkedlists.h"
#include "asterisk/threadstorage.h"
#include "asterisk/test.h"

Go to the source code of this file.

Data Structures

struct  groups
struct  linear_state
struct  path_lock
struct  path_lock_list
struct  zombie
struct  zombies

Defines

#define AST_MAX_FORMATS   10
#define FMT   "%30Lf%9s"
#define RES_EXIT   (1 << 17)
#define RES_REPEAT   (1 << 18)
#define RES_RESTART   ((1 << 19) | RES_REPEAT)
#define RES_UPONE   (1 << 16)

Functions

unsigned int __ast_app_separate_args (char *buf, char delim, int remove_chars, char **array, int arraylen)
 Separate a string into arguments in an array.
static int __ast_play_and_record (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound)
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.
enum ast_getdata_result ast_app_getdata (struct ast_channel *c, const 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, const 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_group_discard (struct ast_channel *chan)
 Discard all group counting for a channel.
int ast_app_group_get_count (const char *group, const char *category)
 Get the current channel count of the specified group and category.
ast_group_infoast_app_group_list_head (void)
 Get the head of the group count list.
int ast_app_group_list_rdlock (void)
 Read Lock the group count list.
int ast_app_group_list_unlock (void)
 Unlock the group count list.
int ast_app_group_list_wrlock (void)
 Write Lock the group count list.
int ast_app_group_match_get_count (const char *groupmatch, const char *category)
 Get the current channel count of all groups that match the specified pattern and category.
int ast_app_group_set_channel (struct ast_channel *chan, const char *data)
 Set the group for a channel, splitting the provided data into group and category, if specified.
int ast_app_group_split_group (const 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.
int ast_app_group_update (struct ast_channel *old, struct ast_channel *new)
 Update all group counting for a channel to a new one.
int ast_app_has_voicemail (const char *mailbox, const char *folder)
 Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the number of messages in the "Urgent" folder.
int ast_app_inboxcount (const char *mailbox, int *newmsgs, int *oldmsgs)
 Determine number of new/old messages in a mailbox.
int ast_app_inboxcount2 (const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
 Determine number of urgent/new/old messages in a mailbox.
int ast_app_messagecount (const char *context, const char *mailbox, const char *folder)
 Check number of messages in a given context, mailbox, and folder.
void ast_app_options2str64 (const struct ast_app_option *options, struct ast_flags64 *flags, char *buf, size_t len)
 Given a list of options array, return an option string based on passed flags.
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.
int ast_app_parse_options64 (const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
 Parses a string containing application options and sets flags/arguments.
int ast_app_parse_timelen (const char *timestr, int *result, enum ast_timelen unit)
 Common routine to parse time lengths, with optional time unit specifier.
int ast_app_run_macro (struct ast_channel *autoservice_chan, struct ast_channel *macro_chan, const char *const macro_name, const char *const macro_args)
 Run a macro on a channel, placing a second channel into autoservice.
int ast_app_sayname (struct ast_channel *chan, const char *mailbox, const char *context)
 Given a mailbox and context, play that mailbox owner's name to the channel specified.
unsigned int ast_app_separate_args (char *buf, char delim, char **array, int arraylen)
void ast_close_fds_above_n (int n)
 Common routine for child processes, to close all fds prior to exec(2).
int ast_control_streamfile (struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *suspend, const char *restart, int skipms, long *offsetms)
 Stream a file with fast forward, pause, reverse, restart.
int ast_dtmf_stream (struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between, unsigned int duration)
 Send DTMF to a channel.
int ast_get_encoded_char (const char *stream, char *result, size_t *consumed)
 Decode an encoded control or extended ASCII character.
char * ast_get_encoded_str (const char *stream, char *result, size_t result_size)
 Decode a stream of encoded control or extended ASCII characters.
void ast_install_vm_functions (int(*has_voicemail_func)(const char *mailbox, const char *folder), int(*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs), int(*inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs), int(*messagecount_func)(const char *context, const char *mailbox, const char *folder), int(*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context))
 Set voicemail function callbacks.
int ast_ivr_menu_run (struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
 Runs an IVR menu.
static 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)
 Stream a filename (or file descriptor) as a generator.
enum AST_LOCK_RESULT ast_lock_path (const char *path)
 Lock a filesystem path.
static enum AST_LOCK_RESULT ast_lock_path_flock (const char *path)
static enum AST_LOCK_RESULT ast_lock_path_lockfile (const char *path)
int ast_play_and_prepend (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence)
 Record a file based on input frm a channel. Recording is performed in 'prepend' mode which works a little differently from normal recordings This function will not play a success message due to post-recording control in the application this was added for.
int ast_play_and_record (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path)
 Record a file based on input from a channel. Use default accept and cancel DTMF. This function will play "auth-thankyou" upon successful recording.
int ast_play_and_record_full (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf)
 Record a file based on input from a channel This function will play "auth-thankyou" upon successful recording.
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.
char * ast_read_textfile (const char *filename)
 Read a file into asterisk.
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.
int ast_safe_fork (int stop_reaper)
 Common routine to safely fork without a chance of a signal handler firing badly in the child.
void ast_safe_fork_cleanup (void)
 Common routine to cleanup after fork'ed process is complete (if reaping was stopped).
void ast_set_lock_type (enum AST_LOCK_TYPE type)
 Set the type of locks used by ast_lock_path().
int ast_str_get_encoded_str (struct ast_str **str, int maxlen, const char *stream)
 Decode a stream of encoded control or extended ASCII characters.
 AST_THREADSTORAGE_PUBLIC (ast_str_thread_global_buf)
void ast_uninstall_vm_functions (void)
int ast_unlock_path (const char *path)
 Unlock a path.
static int ast_unlock_path_flock (const char *path)
static int ast_unlock_path_lockfile (const char *path)
static int ivr_dispatch (struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
static void * linear_alloc (struct ast_channel *chan, void *params)
static int linear_generator (struct ast_channel *chan, void *data, int len, int samples)
static void linear_release (struct ast_channel *chan, void *params)
static int option_exists (struct ast_ivr_menu *menu, char *option)
static int option_matchmore (struct ast_ivr_menu *menu, char *option)
static int parse_options (const struct ast_app_option *options, void *_flags, char **args, char *optstr, int flaglen)
static void path_lock_destroy (struct path_lock *obj)
static int read_newoption (struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
static void * shaun_of_the_dead (void *data)

Variables

static int(*) ast_has_voicemail_func (const char *mailbox, const char *folder) = NULL
static int(*) ast_inboxcount2_func (const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs) = NULL
static int(*) ast_inboxcount_func (const char *mailbox, int *newmsgs, int *oldmsgs) = NULL
static enum AST_LOCK_TYPE ast_lock_type = AST_LOCK_TYPE_LOCKFILE
static int(*) ast_messagecount_func (const char *context, const char *mailbox, const char *folder) = NULL
static int(*) ast_sayname_func (struct ast_channel *chan, const char *mailbox, const char *context) = NULL
static const char default_acceptdtmf [] = "#"
static const char default_canceldtmf [] = ""
static int global_maxsilence = 0
static int global_silence_threshold = 128
static struct ast_generator linearstream
static pthread_t shaun_of_the_dead_thread = AST_PTHREADT_NULL


Detailed Description

Convenient Application Routines.

Author:
Mark Spencer <markster@digium.com>

Definition in file app.c.


Define Documentation

#define AST_MAX_FORMATS   10

Definition at line 97 of file app.c.

#define FMT   "%30Lf%9s"

Referenced by ast_app_parse_timelen().

#define RES_EXIT   (1 << 17)

Definition at line 1646 of file app.c.

Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().

#define RES_REPEAT   (1 << 18)

Definition at line 1647 of file app.c.

Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().

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

Definition at line 1648 of file app.c.

Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().

#define RES_UPONE   (1 << 16)

Definition at line 1645 of file app.c.

Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().


Function Documentation

unsigned int __ast_app_separate_args ( char *  buf,
char  delim,
int  remove_chars,
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
remove_chars Remove backslashes and quote characters, while parsing
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 1255 of file app.c.

References paren, and quote().

Referenced by ast_app_separate_args().

01256 {
01257    int argc;
01258    char *scan, *wasdelim = NULL;
01259    int paren = 0, quote = 0, bracket = 0;
01260 
01261    if (!array || !arraylen) {
01262       return 0;
01263    }
01264 
01265    memset(array, 0, arraylen * sizeof(*array));
01266 
01267    if (!buf) {
01268       return 0;
01269    }
01270 
01271    scan = buf;
01272 
01273    for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
01274       array[argc] = scan;
01275       for (; *scan; scan++) {
01276          if (*scan == '(') {
01277             paren++;
01278          } else if (*scan == ')') {
01279             if (paren) {
01280                paren--;
01281             }
01282          } else if (*scan == '[') {
01283             bracket++;
01284          } else if (*scan == ']') {
01285             if (bracket) {
01286                bracket--;
01287             }
01288          } else if (*scan == '"' && delim != '"') {
01289             quote = quote ? 0 : 1;
01290             if (remove_chars) {
01291                /* Remove quote character from argument */
01292                memmove(scan, scan + 1, strlen(scan));
01293                scan--;
01294             }
01295          } else if (*scan == '\\') {
01296             if (remove_chars) {
01297                /* Literal character, don't parse */
01298                memmove(scan, scan + 1, strlen(scan));
01299             } else {
01300                scan++;
01301             }
01302          } else if ((*scan == delim) && !paren && !quote && !bracket) {
01303             wasdelim = scan;
01304             *scan++ = '\0';
01305             break;
01306          }
01307       }
01308    }
01309 
01310    /* If the last character in the original string was the delimiter, then
01311     * there is one additional argument. */
01312    if (*scan || (scan > buf && (scan - 1) == wasdelim)) {
01313       array[argc++] = scan;
01314    }
01315 
01316    return argc;
01317 }

static int __ast_play_and_record ( struct ast_channel chan,
const char *  playfile,
const char *  recordfile,
int  maxtime,
const char *  fmt,
int *  duration,
int *  sound_duration,
int  beep,
int  silencethreshold,
int  maxsilence,
const char *  path,
int  prepend,
const char *  acceptdtmf,
const char *  canceldtmf,
int  skip_confirmation_sound 
) [static]

Optionally play a sound file or a beep, then record audio and video from the channel.

Parameters:
chan Channel to playback to/record from.
playfile Filename of sound to play before recording begins.
recordfile Filename to record to.
maxtime Maximum length of recording (in seconds).
fmt Format(s) to record message in. Multiple formats may be specified by separating them with a '|'.
duration Where to store actual length of the recorded message (in milliseconds).
sound_duration Where to store the length of the recorded message (in milliseconds), minus any silence
beep Whether to play a beep before starting to record.
silencethreshold 
maxsilence Length of silence that will end a recording (in milliseconds).
path Optional filesystem path to unlock.
prepend If true, prepend the recorded audio to an existing file and follow prepend mode recording rules
acceptdtmf DTMF digits that will end the recording.
canceldtmf DTMF digits that will cancel the recording.
skip_confirmation_sound If true, don't play auth-thankyou at end. Nice for custom recording prompts in apps.
Return values:
-1 failure or hangup
'S' Recording ended from silence timeout
't' Recording ended from the message exceeding the maximum duration, or via DTMF in prepend mode
dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.

Note:
Instead of asking how much time passed (end - start), calculate the number of seconds of audio which actually went into the file. This fixes a problem where audio is stopped up on the network and never gets to us.
Note that we still want to use the number of seconds passed for the max message, otherwise we could get a situation where this stream is never closed (which would create a resource leak).

Note:
If we ended with silence, trim all but the first 200ms of silence off the recording. However, if we ended with '#', we don't want to trim ANY part of the recording.

Same logic as above.

Definition at line 740 of file app.c.

References ast_channel_start_silence_generator(), AST_CONTROL_VIDUPDATE, ast_copy_string(), ast_debug, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), AST_FILE_MODE, AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_indicate(), ast_log(), AST_MAX_FORMATS, ast_opt_transmit_silence, ast_play_and_wait(), ast_read(), ast_set_read_format(), ast_strdupa, ast_stream_and_wait(), ast_unlock_path(), ast_verb, ast_waitfor(), ast_writefile(), ast_writestream(), comment, f, LOG_WARNING, ast_channel::name, ast_channel::readformat, strsep(), and ast_dsp::totalsilence.

Referenced by ast_play_and_prepend(), ast_play_and_record(), and ast_play_and_record_full().

00741 {
00742    int d = 0;
00743    char *fmts;
00744    char comment[256];
00745    int x, fmtcnt = 1, res = -1, outmsg = 0;
00746    struct ast_filestream *others[AST_MAX_FORMATS];
00747    char *sfmt[AST_MAX_FORMATS];
00748    char *stringp = NULL;
00749    time_t start, end;
00750    struct ast_dsp *sildet = NULL;   /* silence detector dsp */
00751    int totalsilence = 0;
00752    int dspsilence = 0;
00753    int olddspsilence = 0;
00754    int rfmt = 0;
00755    struct ast_silence_generator *silgen = NULL;
00756    char prependfile[80];
00757 
00758    if (silencethreshold < 0) {
00759       silencethreshold = global_silence_threshold;
00760    }
00761 
00762    if (maxsilence < 0) {
00763       maxsilence = global_maxsilence;
00764    }
00765 
00766    /* barf if no pointer passed to store duration in */
00767    if (!duration) {
00768       ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00769       return -1;
00770    }
00771 
00772    ast_debug(1, "play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00773    snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00774 
00775    if (playfile || beep) {
00776       if (!beep) {
00777          d = ast_play_and_wait(chan, playfile);
00778       }
00779       if (d > -1) {
00780          d = ast_stream_and_wait(chan, "beep", "");
00781       }
00782       if (d < 0) {
00783          return -1;
00784       }
00785    }
00786 
00787    if (prepend) {
00788       ast_copy_string(prependfile, recordfile, sizeof(prependfile));
00789       strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00790    }
00791 
00792    fmts = ast_strdupa(fmt);
00793 
00794    stringp = fmts;
00795    strsep(&stringp, "|");
00796    ast_debug(1, "Recording Formats: sfmts=%s\n", fmts);
00797    sfmt[0] = ast_strdupa(fmts);
00798 
00799    while ((fmt = strsep(&stringp, "|"))) {
00800       if (fmtcnt > AST_MAX_FORMATS - 1) {
00801          ast_log(LOG_WARNING, "Please increase AST_MAX_FORMATS in file.h\n");
00802          break;
00803       }
00804       sfmt[fmtcnt++] = ast_strdupa(fmt);
00805    }
00806 
00807    end = start = time(NULL);  /* pre-initialize end to be same as start in case we never get into loop */
00808    for (x = 0; x < fmtcnt; x++) {
00809       others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
00810       ast_verb(3, "x=%d, open writing:  %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
00811 
00812       if (!others[x]) {
00813          break;
00814       }
00815    }
00816 
00817    if (path) {
00818       ast_unlock_path(path);
00819    }
00820 
00821    if (maxsilence > 0) {
00822       sildet = ast_dsp_new(); /* Create the silence detector */
00823       if (!sildet) {
00824          ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00825          return -1;
00826       }
00827       ast_dsp_set_threshold(sildet, silencethreshold);
00828       rfmt = chan->readformat;
00829       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00830       if (res < 0) {
00831          ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00832          ast_dsp_free(sildet);
00833          return -1;
00834       }
00835    }
00836 
00837    if (!prepend) {
00838       /* Request a video update */
00839       ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00840 
00841       if (ast_opt_transmit_silence) {
00842          silgen = ast_channel_start_silence_generator(chan);
00843       }
00844    }
00845 
00846    if (x == fmtcnt) {
00847       /* Loop forever, writing the packets we read to the writer(s), until
00848          we read a digit or get a hangup */
00849       struct ast_frame *f;
00850       for (;;) {
00851          if (!(res = ast_waitfor(chan, 2000))) {
00852             ast_debug(1, "One waitfor failed, trying another\n");
00853             /* Try one more time in case of masq */
00854             if (!(res = ast_waitfor(chan, 2000))) {
00855                ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00856                res = -1;
00857             }
00858          }
00859 
00860          if (res < 0) {
00861             f = NULL;
00862             break;
00863          }
00864          if (!(f = ast_read(chan))) {
00865             break;
00866          }
00867          if (f->frametype == AST_FRAME_VOICE) {
00868             /* write each format */
00869             for (x = 0; x < fmtcnt; x++) {
00870                if (prepend && !others[x]) {
00871                   break;
00872                }
00873                res = ast_writestream(others[x], f);
00874             }
00875 
00876             /* Silence Detection */
00877             if (maxsilence > 0) {
00878                dspsilence = 0;
00879                ast_dsp_silence(sildet, f, &dspsilence);
00880                if (olddspsilence > dspsilence) {
00881                   totalsilence += olddspsilence;
00882                }
00883                olddspsilence = dspsilence;
00884 
00885                if (dspsilence > maxsilence) {
00886                   /* Ended happily with silence */
00887                   ast_verb(3, "Recording automatically stopped after a silence of %d seconds\n", dspsilence/1000);
00888                   res = 'S';
00889                   outmsg = 2;
00890                   break;
00891                }
00892             }
00893             /* Exit on any error */
00894             if (res) {
00895                ast_log(LOG_WARNING, "Error writing frame\n");
00896                break;
00897             }
00898          } else if (f->frametype == AST_FRAME_VIDEO) {
00899             /* Write only once */
00900             ast_writestream(others[0], f);
00901          } else if (f->frametype == AST_FRAME_DTMF) {
00902             if (prepend) {
00903             /* stop recording with any digit */
00904                ast_verb(3, "User ended message by pressing %c\n", f->subclass.integer);
00905                res = 't';
00906                outmsg = 2;
00907                break;
00908             }
00909             if (strchr(acceptdtmf, f->subclass.integer)) {
00910                ast_verb(3, "User ended message by pressing %c\n", f->subclass.integer);
00911                res = f->subclass.integer;
00912                outmsg = 2;
00913                break;
00914             }
00915             if (strchr(canceldtmf, f->subclass.integer)) {
00916                ast_verb(3, "User cancelled message by pressing %c\n", f->subclass.integer);
00917                res = f->subclass.integer;
00918                outmsg = 0;
00919                break;
00920             }
00921          }
00922          if (maxtime) {
00923             end = time(NULL);
00924             if (maxtime < (end - start)) {
00925                ast_verb(3, "Took too long, cutting it short...\n");
00926                res = 't';
00927                outmsg = 2;
00928                break;
00929             }
00930          }
00931          ast_frfree(f);
00932       }
00933       if (!f) {
00934          ast_verb(3, "User hung up\n");
00935          res = -1;
00936          outmsg = 1;
00937       } else {
00938          ast_frfree(f);
00939       }
00940    } else {
00941       ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00942    }
00943 
00944    if (!prepend) {
00945       if (silgen) {
00946          ast_channel_stop_silence_generator(chan, silgen);
00947       }
00948    }
00949 
00950    /*!\note
00951     * Instead of asking how much time passed (end - start), calculate the number
00952     * of seconds of audio which actually went into the file.  This fixes a
00953     * problem where audio is stopped up on the network and never gets to us.
00954     *
00955     * Note that we still want to use the number of seconds passed for the max
00956     * message, otherwise we could get a situation where this stream is never
00957     * closed (which would create a resource leak).
00958     */
00959    *duration = others[0] ? ast_tellstream(others[0]) / 8000 : 0;
00960    if (sound_duration) {
00961       *sound_duration = *duration;
00962    }
00963 
00964    if (!prepend) {
00965       /* Reduce duration by a total silence amount */
00966       if (olddspsilence <= dspsilence) {
00967          totalsilence += dspsilence;
00968       }
00969 
00970       if (sound_duration) {
00971          if (totalsilence > 0) {
00972             *sound_duration -= (totalsilence - 200) / 1000;
00973          }
00974          if (*sound_duration < 0) {
00975             *sound_duration = 0;
00976          }
00977       }
00978 
00979       if (dspsilence > 0) {
00980          *duration -= (dspsilence - 200) / 1000;
00981       }
00982       if (*duration < 0) {
00983          *duration = 0;
00984       }
00985 
00986       for (x = 0; x < fmtcnt; x++) {
00987          if (!others[x]) {
00988             break;
00989          }
00990          /*!\note
00991           * If we ended with silence, trim all but the first 200ms of silence
00992           * off the recording.  However, if we ended with '#', we don't want
00993           * to trim ANY part of the recording.
00994           */
00995          if (res > 0 && dspsilence) {
00996                                 /* rewind only the trailing silence */
00997             ast_stream_rewind(others[x], dspsilence - 200);
00998          }
00999          ast_truncstream(others[x]);
01000          ast_closestream(others[x]);
01001       }
01002    }
01003 
01004    if (prepend && outmsg) {
01005       struct ast_filestream *realfiles[AST_MAX_FORMATS];
01006       struct ast_frame *fr;
01007 
01008       for (x = 0; x < fmtcnt; x++) {
01009          snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
01010          realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
01011          if (!others[x] || !realfiles[x]) {
01012             break;
01013          }
01014          /*!\note Same logic as above. */
01015          if (dspsilence) {
01016             ast_stream_rewind(others[x], dspsilence - 200);
01017          }
01018          ast_truncstream(others[x]);
01019          /* add the original file too */
01020          while ((fr = ast_readframe(realfiles[x]))) {
01021             ast_writestream(others[x], fr);
01022             ast_frfree(fr);
01023          }
01024          ast_closestream(others[x]);
01025          ast_closestream(realfiles[x]);
01026          ast_filerename(prependfile, recordfile, sfmt[x]);
01027          ast_verb(4, "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
01028          ast_filedelete(prependfile, sfmt[x]);
01029       }
01030    }
01031    if (rfmt && ast_set_read_format(chan, rfmt)) {
01032       ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
01033    }
01034    if ((outmsg == 2) && (!skip_confirmation_sound)) {
01035       ast_stream_and_wait(chan, "auth-thankyou", "");
01036    }
01037    if (sildet) {
01038       ast_dsp_free(sildet);
01039    }
01040    return res;
01041 }

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.

Parameters:
chan struct.
context 
collect 
size 
maxlen 
timeout timeout in milliseconds
Returns:
0 if extension does not exist, 1 if extension exists

Definition at line 115 of file app.c.

References ast_get_indication_tone(), ast_ignore_pattern(), ast_log(), ast_matchmore_extension(), ast_playtones_start(), ast_playtones_stop(), ast_tone_zone_sound_unref(), ast_waitfordigit(), ast_channel::caller, ast_tone_zone_sound::data, ast_pbx::dtimeoutms, ast_party_caller::id, LOG_NOTICE, ast_party_id::number, ast_channel::pbx, S_COR, ast_party_number::str, ast_party_number::valid, and ast_channel::zone.

Referenced by builtin_atxfer(), builtin_blindtransfer(), and grab_transfer().

00116 {
00117    struct ast_tone_zone_sound *ts;
00118    int res = 0, x = 0;
00119 
00120    if (maxlen > size) {
00121       maxlen = size;
00122    }
00123 
00124    if (!timeout) {
00125       if (chan->pbx && chan->pbx->dtimeoutms) {
00126          timeout = chan->pbx->dtimeoutms;
00127       } else {
00128          timeout = 5000;
00129       }
00130    }
00131 
00132    if ((ts = ast_get_indication_tone(chan->zone, "dial"))) {
00133       res = ast_playtones_start(chan, 0, ts->data, 0);
00134       ts = ast_tone_zone_sound_unref(ts);
00135    } else {
00136       ast_log(LOG_NOTICE, "Huh....? no dial for indications?\n");
00137    }
00138 
00139    for (x = strlen(collect); x < maxlen; ) {
00140       res = ast_waitfordigit(chan, timeout);
00141       if (!ast_ignore_pattern(context, collect)) {
00142          ast_playtones_stop(chan);
00143       }
00144       if (res < 1) {
00145          break;
00146       }
00147       if (res == '#') {
00148          break;
00149       }
00150       collect[x++] = res;
00151       if (!ast_matchmore_extension(chan, context, collect, 1,
00152          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL))) {
00153          break;
00154       }
00155    }
00156 
00157    if (res >= 0) {
00158       res = ast_exists_extension(chan, context, collect, 1,
00159          S_COR(chan->caller.id.number.valid, chan->caller.id.number.str, NULL)) ? 1 : 0;
00160    }
00161 
00162    return res;
00163 }

enum ast_getdata_result ast_app_getdata ( struct ast_channel c,
const char *  prompt,
char *  s,
int  maxlen,
int  timeout 
)

Plays a stream and gets DTMF data from a channel.

Parameters:
c The channel to read from
prompt The file to stream to the channel
s The string to read in to. Must be at least the size of your length
maxlen How many digits to read (maximum)
timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for "ludicrous time" (essentially never times out)

Definition at line 173 of file app.c.

References AST_GETDATA_EMPTY_END_TERMINATED, ast_readstring(), ast_strdupa, ast_streamfile(), ast_strlen_zero(), ast_pbx::dtimeoutms, ast_channel::language, ast_channel::pbx, ast_pbx::rtimeoutms, and strsep().

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

00174 {
00175    int res = 0, to, fto;
00176    char *front, *filename;
00177 
00178    /* XXX Merge with full version? XXX */
00179 
00180    if (maxlen)
00181       s[0] = '\0';
00182 
00183    if (!prompt)
00184       prompt = "";
00185 
00186    filename = ast_strdupa(prompt);
00187    while ((front = strsep(&filename, "&"))) {
00188       if (!ast_strlen_zero(front)) {
00189          res = ast_streamfile(c, front, c->language);
00190          if (res)
00191             continue;
00192       }
00193       if (ast_strlen_zero(filename)) {
00194          /* set timeouts for the last prompt */
00195          fto = c->pbx ? c->pbx->rtimeoutms : 6000;
00196          to = c->pbx ? c->pbx->dtimeoutms : 2000;
00197 
00198          if (timeout > 0) {
00199             fto = to = timeout;
00200          }
00201          if (timeout < 0) {
00202             fto = to = 1000000000;
00203          }
00204       } else {
00205          /* there is more than one prompt, so
00206           * get rid of the long timeout between
00207           * prompts, and make it 50ms */
00208          fto = 50;
00209          to = c->pbx ? c->pbx->dtimeoutms : 2000;
00210       }
00211       res = ast_readstring(c, s, maxlen, to, fto, "#");
00212       if (res == AST_GETDATA_EMPTY_END_TERMINATED) {
00213          return res;
00214       }
00215       if (!ast_strlen_zero(s)) {
00216          return res;
00217       }
00218    }
00219 
00220    return res;
00221 }

int ast_app_getdata_full ( struct ast_channel c,
const 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 226 of file app.c.

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

Referenced by handle_getdata().

00227 {
00228    int res, to = 2000, fto = 6000;
00229 
00230    if (!ast_strlen_zero(prompt)) {
00231       res = ast_streamfile(c, prompt, c->language);
00232       if (res < 0) {
00233          return res;
00234       }
00235    }
00236 
00237    if (timeout > 0) {
00238       fto = to = timeout;
00239    }
00240    if (timeout < 0) {
00241       fto = to = 1000000000;
00242    }
00243 
00244    res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
00245 
00246    return res;
00247 }

int ast_app_group_discard ( struct ast_channel chan  ) 

Discard all group counting for a channel.

Definition at line 1215 of file app.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_group_info::chan, and ast_group_info::group_list.

Referenced by ast_channel_destructor().

01216 {
01217    struct ast_group_info *gi = NULL;
01218 
01219    AST_RWLIST_WRLOCK(&groups);
01220    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01221       if (gi->chan == chan) {
01222          AST_RWLIST_REMOVE_CURRENT(group_list);
01223          ast_free(gi);
01224       }
01225    }
01226    AST_RWLIST_TRAVERSE_SAFE_END;
01227    AST_RWLIST_UNLOCK(&groups);
01228 
01229    return 0;
01230 }

int ast_app_group_get_count ( const char *  group,
const char *  category 
)

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

Definition at line 1137 of file app.c.

References AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strlen_zero(), ast_group_info::category, ast_group_info::group, and ast_group_info::group_list.

Referenced by group_count_function_read().

01138 {
01139    struct ast_group_info *gi = NULL;
01140    int count = 0;
01141 
01142    if (ast_strlen_zero(group)) {
01143       return 0;
01144    }
01145 
01146    AST_RWLIST_RDLOCK(&groups);
01147    AST_RWLIST_TRAVERSE(&groups, gi, group_list) {
01148       if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01149          count++;
01150       }
01151    }
01152    AST_RWLIST_UNLOCK(&groups);
01153 
01154    return count;
01155 }

struct ast_group_info* ast_app_group_list_head ( void   ) 

Get the head of the group count list.

Definition at line 1242 of file app.c.

References AST_RWLIST_FIRST.

Referenced by group_count_function_read(), group_function_read(), group_list_function_read(), and group_show_channels().

01243 {
01244    return AST_RWLIST_FIRST(&groups);
01245 }

int ast_app_group_list_rdlock ( void   ) 

Read Lock the group count list.

Definition at line 1237 of file app.c.

References AST_RWLIST_RDLOCK.

Referenced by group_count_function_read(), group_function_read(), group_list_function_read(), and group_show_channels().

01238 {
01239    return AST_RWLIST_RDLOCK(&groups);
01240 }

int ast_app_group_list_unlock ( void   ) 

Unlock the group count list.

Definition at line 1247 of file app.c.

References AST_RWLIST_UNLOCK.

Referenced by group_count_function_read(), group_function_read(), group_list_function_read(), and group_show_channels().

01248 {
01249    return AST_RWLIST_UNLOCK(&groups);
01250 }

int ast_app_group_list_wrlock ( void   ) 

Write Lock the group count list.

Definition at line 1232 of file app.c.

References AST_RWLIST_WRLOCK.

01233 {
01234    return AST_RWLIST_WRLOCK(&groups);
01235 }

int ast_app_group_match_get_count ( const char *  groupmatch,
const char *  category 
)

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

Definition at line 1157 of file app.c.

References ast_log(), AST_RWLIST_RDLOCK, AST_RWLIST_TRAVERSE, AST_RWLIST_UNLOCK, ast_strlen_zero(), ast_group_info::category, ast_group_info::group, ast_group_info::group_list, LOG_ERROR, and LOG_NOTICE.

Referenced by group_match_count_function_read().

01158 {
01159    struct ast_group_info *gi = NULL;
01160    regex_t regexbuf_group;
01161    regex_t regexbuf_category;
01162    int count = 0;
01163 
01164    if (ast_strlen_zero(groupmatch)) {
01165       ast_log(LOG_NOTICE, "groupmatch empty\n");
01166       return 0;
01167    }
01168 
01169    /* if regex compilation fails, return zero matches */
01170    if (regcomp(&regexbuf_group, groupmatch, REG_EXTENDED | REG_NOSUB)) {
01171       ast_log(LOG_ERROR, "Regex compile failed on: %s\n", groupmatch);
01172       return 0;
01173    }
01174 
01175    if (!ast_strlen_zero(category) && regcomp(&regexbuf_category, category, REG_EXTENDED | REG_NOSUB)) {
01176       ast_log(LOG_ERROR, "Regex compile failed on: %s\n", category);
01177       return 0;
01178    }
01179 
01180    AST_RWLIST_RDLOCK(&groups);
01181    AST_RWLIST_TRAVERSE(&groups, gi, group_list) {
01182       if (!regexec(&regexbuf_group, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !regexec(&regexbuf_category, gi->category, 0, NULL, 0)))) {
01183          count++;
01184       }
01185    }
01186    AST_RWLIST_UNLOCK(&groups);
01187 
01188    regfree(&regexbuf_group);
01189    if (!ast_strlen_zero(category)) {
01190       regfree(&regexbuf_category);
01191    }
01192 
01193    return count;
01194 }

int ast_app_group_set_channel ( struct ast_channel chan,
const char *  data 
)

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

Definition at line 1090 of file app.c.

References ast_app_group_split_group(), AST_RWLIST_INSERT_TAIL, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_strlen_zero(), calloc, ast_group_info::category, ast_group_info::chan, free, ast_group_info::group, ast_group_info::group_list, and len().

Referenced by dial_exec_full(), and group_function_write().

01091 {
01092    int res = 0;
01093    char group[80] = "", category[80] = "";
01094    struct ast_group_info *gi = NULL;
01095    size_t len = 0;
01096 
01097    if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
01098       return -1;
01099    }
01100 
01101    /* Calculate memory we will need if this is new */
01102    len = sizeof(*gi) + strlen(group) + 1;
01103    if (!ast_strlen_zero(category)) {
01104       len += strlen(category) + 1;
01105    }
01106 
01107    AST_RWLIST_WRLOCK(&groups);
01108    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01109       if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01110          AST_RWLIST_REMOVE_CURRENT(group_list);
01111          free(gi);
01112          break;
01113       }
01114    }
01115    AST_RWLIST_TRAVERSE_SAFE_END;
01116 
01117    if (ast_strlen_zero(group)) {
01118       /* Enable unsetting the group */
01119    } else if ((gi = calloc(1, len))) {
01120       gi->chan = chan;
01121       gi->group = (char *) gi + sizeof(*gi);
01122       strcpy(gi->group, group);
01123       if (!ast_strlen_zero(category)) {
01124          gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1;
01125          strcpy(gi->category, category);
01126       }
01127       AST_RWLIST_INSERT_TAIL(&groups, gi, group_list);
01128    } else {
01129       res = -1;
01130    }
01131 
01132    AST_RWLIST_UNLOCK(&groups);
01133 
01134    return res;
01135 }

int ast_app_group_split_group ( const 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 1063 of file app.c.

References ast_copy_string(), and ast_strlen_zero().

Referenced by ast_app_group_set_channel(), group_count_function_read(), and group_match_count_function_read().

01064 {
01065    int res = 0;
01066    char tmp[256];
01067    char *grp = NULL, *cat = NULL;
01068 
01069    if (!ast_strlen_zero(data)) {
01070       ast_copy_string(tmp, data, sizeof(tmp));
01071       grp = tmp;
01072       if ((cat = strchr(tmp, '@'))) {
01073          *cat++ = '\0';
01074       }
01075    }
01076 
01077    if (!ast_strlen_zero(grp)) {
01078       ast_copy_string(group, grp, group_max);
01079    } else {
01080       *group = '\0';
01081    }
01082 
01083    if (!ast_strlen_zero(cat)) {
01084       ast_copy_string(category, cat, category_max);
01085    }
01086 
01087    return res;
01088 }

int ast_app_group_update ( struct ast_channel old,
struct ast_channel new 
)

Update all group counting for a channel to a new one.

Definition at line 1196 of file app.c.

References ast_free, AST_RWLIST_REMOVE_CURRENT, AST_RWLIST_TRAVERSE_SAFE_BEGIN, AST_RWLIST_TRAVERSE_SAFE_END, AST_RWLIST_UNLOCK, AST_RWLIST_WRLOCK, ast_group_info::chan, and ast_group_info::group_list.

Referenced by ast_do_masquerade(), and check_bridge().

01197 {
01198    struct ast_group_info *gi = NULL;
01199 
01200    AST_RWLIST_WRLOCK(&groups);
01201    AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01202       if (gi->chan == old) {
01203          gi->chan = new;
01204       } else if (gi->chan == new) {
01205          AST_RWLIST_REMOVE_CURRENT(group_list);
01206          ast_free(gi);
01207       }
01208    }
01209    AST_RWLIST_TRAVERSE_SAFE_END;
01210    AST_RWLIST_UNLOCK(&groups);
01211 
01212    return 0;
01213 }

int ast_app_has_voicemail ( const char *  mailbox,
const char *  folder 
)

Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the number of messages in the "Urgent" folder.

Return values:
1 Mailbox has voicemail
0 No new voicemail in specified mailbox
-1 Failure
Since:
1.0

Definition at line 299 of file app.c.

References ast_has_voicemail_func, and ast_verb.

Referenced by action_mailboxstatus(), has_voicemail(), notify_new_message(), play_dialtone(), poll_mailbox(), run_externnotify(), skinny_register(), and unistim_send_mwi_to_peer().

00300 {
00301    static int warned = 0;
00302    if (ast_has_voicemail_func) {
00303       return ast_has_voicemail_func(mailbox, folder);
00304    }
00305 
00306    if (warned++ % 10 == 0) {
00307       ast_verb(3, "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
00308    }
00309    return 0;
00310 }

int ast_app_inboxcount ( const char *  mailbox,
int *  newmsgs,
int *  oldmsgs 
)

Determine number of new/old messages in a mailbox.

Since:
1.0
Parameters:
[in] mailbox Mailbox specification in the format mbox[][&mbox2[]][...]
[out] newmsgs Number of messages in the "INBOX" folder. Includes number of messages in the "Urgent" folder, if any.
[out] oldmsgs Number of messages in the "Old" folder.
Return values:
0 Success
-1 Failure

Definition at line 313 of file app.c.

References ast_inboxcount_func, and ast_verb.

Referenced by sip_send_mwi_to_peer(), and update_registry().

00314 {
00315    static int warned = 0;
00316    if (newmsgs) {
00317       *newmsgs = 0;
00318    }
00319    if (oldmsgs) {
00320       *oldmsgs = 0;
00321    }
00322    if (ast_inboxcount_func) {
00323       return ast_inboxcount_func(mailbox, newmsgs, oldmsgs);
00324    }
00325 
00326    if (warned++ % 10 == 0) {
00327       ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
00328    }
00329 
00330    return 0;
00331 }

int ast_app_inboxcount2 ( const char *  mailbox,
int *  urgentmsgs,
int *  newmsgs,
int *  oldmsgs 
)

Determine number of urgent/new/old messages in a mailbox.

Parameters:
[in] mailbox the mailbox context to use
[out] urgentmsgs the urgent message count
[out] newmsgs the new message count
[out] oldmsgs the old message count
Returns:
Returns 0 for success, negative upon error
Since:
1.6.1

Definition at line 333 of file app.c.

References ast_inboxcount2_func, ast_inboxcount_func, and ast_verb.

Referenced by action_mailboxcount(), notify_new_message(), and vm_execmain().

00334 {
00335    static int warned = 0;
00336    if (newmsgs) {
00337       *newmsgs = 0;
00338    }
00339    if (oldmsgs) {
00340       *oldmsgs = 0;
00341    }
00342    if (urgentmsgs) {
00343       *urgentmsgs = 0;
00344    }
00345    if (ast_inboxcount_func) {
00346       return ast_inboxcount2_func(mailbox, urgentmsgs, newmsgs, oldmsgs);
00347    }
00348 
00349    if (warned++ % 10 == 0) {
00350       ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
00351    }
00352 
00353    return 0;
00354 }

int ast_app_messagecount ( const char *  context,
const char *  mailbox,
const char *  folder 
)

Check number of messages in a given context, mailbox, and folder.

Since:
1.4
Parameters:
[in] context Mailbox context
[in] mailbox Mailbox number
[in] folder Mailbox folder
Returns:
Number of messages in the given context, mailbox, and folder. If folder is NULL, folder "INBOX" is assumed. If folder is "INBOX", includes number of messages in the "Urgent" folder.

Definition at line 364 of file app.c.

References ast_messagecount_func, and ast_verb.

Referenced by acf_vmcount_exec().

00365 {
00366    static int warned = 0;
00367    if (ast_messagecount_func) {
00368       return ast_messagecount_func(context, mailbox, folder);
00369    }
00370 
00371    if (!warned) {
00372       warned++;
00373       ast_verb(3, "Message count requested for mailbox %s@%s/%s but voicemail not loaded.\n", mailbox, context, folder);
00374    }
00375 
00376    return 0;
00377 }

void ast_app_options2str64 ( const struct ast_app_option options,
struct ast_flags64 flags,
char *  buf,
size_t  len 
)

Given a list of options array, return an option string based on passed flags.

Parameters:
options The array of possible options declared with AST_APP_OPTIONS
flags The flags of the options that you wish to populate the buffer with
buf The buffer to fill with the string of options
len The maximum length of buf

Definition at line 1978 of file app.c.

References ast_test_flag64, and ast_flags64::flags.

01979 {
01980    unsigned int i, found = 0;
01981    for (i = 32; i < 128 && found < len; i++) {
01982       if (ast_test_flag64(flags, options[i].flag)) {
01983          buf[found++] = i;
01984       }
01985    }
01986    buf[found] = '\0';
01987 }

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 1968 of file app.c.

References ast_flags64::flags, and parse_options().

Referenced by app_exec(), auth_exec(), bridge_exec(), cdr_read(), cdr_write(), chanspy_exec(), confbridge_exec(), connectedline_write(), controlplayback_exec(), directory_exec(), disa_exec(), dundi_query_read(), dundifunc_read(), extenspy_exec(), handle_options(), hint_read(), minivm_accmess_exec(), minivm_greet_exec(), minivm_record_exec(), mixmonitor_exec(), page_exec(), park_call_exec(), pbx_builtin_background(), pbx_builtin_resetcdr(), pbx_builtin_waitexten(), read_exec(), readexten_exec(), realtime_common(), receivefax_exec(), record_exec(), redirecting_write(), sendfax_exec(), sendurl_exec(), sig_pri_call(), sla_trunk_exec(), smdi_msg_retrieve_read(), sms_exec(), softhangup_exec(), speech_background(), vm_exec(), vm_execmain(), and volume_write().

01969 {
01970    return parse_options(options, flags, args, optstr, 32);
01971 }

int ast_app_parse_options64 ( const struct ast_app_option options,
struct ast_flags64 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 64-bit 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 1973 of file app.c.

References ast_flags64::flags, and parse_options().

Referenced by conf_exec(), and dial_exec_full().

01974 {
01975    return parse_options(options, flags, args, optstr, 64);
01976 }

int ast_app_parse_timelen ( const char *  timestr,
int *  result,
enum ast_timelen  defunit 
)

Common routine to parse time lengths, with optional time unit specifier.

Parameters:
[in] timestr String to parse
[in] defunit Default unit type
[out] result Resulting value, specified in milliseconds
Return values:
0 Success
-1 Failure
Since:
1.8

Definition at line 2178 of file app.c.

References FMT, TIMELEN_HOURS, TIMELEN_MILLISECONDS, TIMELEN_MINUTES, and TIMELEN_SECONDS.

Referenced by ast_eivr_senddtmf(), pbx_builtin_wait(), pbx_builtin_waitexten(), and senddtmf_exec().

02179 {
02180    int res;
02181    char u[10];
02182 #ifdef HAVE_LONG_DOUBLE_WIDER
02183    long double amount;
02184    #define FMT "%30Lf%9s"
02185 #else
02186    double amount;
02187    #define FMT "%30lf%9s"
02188 #endif
02189    if (!timestr) {
02190       return -1;
02191    }
02192 
02193    if ((res = sscanf(timestr, FMT, &amount, u)) == 0) {
02194 #undef FMT
02195       return -1;
02196    } else if (res == 2) {
02197       switch (u[0]) {
02198       case 'h':
02199       case 'H':
02200          unit = TIMELEN_HOURS;
02201          break;
02202       case 's':
02203       case 'S':
02204          unit = TIMELEN_SECONDS;
02205          break;
02206       case 'm':
02207       case 'M':
02208          if (toupper(u[1]) == 'S') {
02209             unit = TIMELEN_MILLISECONDS;
02210          } else if (u[1] == '\0') {
02211             unit = TIMELEN_MINUTES;
02212          }
02213          break;
02214       }
02215    }
02216 
02217    switch (unit) {
02218    case TIMELEN_HOURS:
02219       amount *= 60;
02220       /* fall-through */
02221    case TIMELEN_MINUTES:
02222       amount *= 60;
02223       /* fall-through */
02224    case TIMELEN_SECONDS:
02225       amount *= 1000;
02226       /* fall-through */
02227    case TIMELEN_MILLISECONDS:
02228       ;
02229    }
02230    *result = amount > INT_MAX ? INT_MAX : (int) amount;
02231    return 0;
02232 }

int ast_app_run_macro ( struct ast_channel autoservice_chan,
struct ast_channel macro_chan,
const char *const   macro_name,
const char *const   macro_args 
)

Run a macro on a channel, placing a second channel into autoservice.

Since:
1.8
This is a shorthand method that makes it very easy to run a macro on any given channel. It is perfectly reasonable to supply a NULL autoservice_chan here in case there is no channel to place into autoservice. It is very important that the autoservice_chan parameter is not locked prior to calling ast_app_run_macro. A deadlock could result, otherwise.

Parameters:
autoservice_chan A channel to place into autoservice while the macro is run
macro_chan The channel to run the macro on
macro_name The name of the macro to run
macro_args The arguments to pass to the macro
Return values:
0 success
-1 failure

Definition at line 249 of file app.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_log(), ast_strlen_zero(), LOG_WARNING, pbx_exec(), pbx_findapp(), and S_OR.

Referenced by ast_channel_connected_line_macro(), ast_channel_redirecting_macro(), and generic_recall().

00250 {
00251    struct ast_app *macro_app;
00252    int res;
00253    char buf[1024];
00254 
00255    macro_app = pbx_findapp("Macro");
00256    if (!macro_app) {
00257       ast_log(LOG_WARNING, "Cannot run macro '%s' because the 'Macro' application in not available\n", macro_name);
00258       return -1;
00259    }
00260    snprintf(buf, sizeof(buf), "%s%s%s", macro_name, ast_strlen_zero(macro_args) ? "" : ",", S_OR(macro_args, ""));
00261    if (autoservice_chan) {
00262       ast_autoservice_start(autoservice_chan);
00263    }
00264    res = pbx_exec(macro_chan, macro_app, buf);
00265    if (autoservice_chan) {
00266       ast_autoservice_stop(autoservice_chan);
00267    }
00268    return res;
00269 }

int ast_app_sayname ( struct ast_channel chan,
const char *  mailbox,
const char *  context 
)

Given a mailbox and context, play that mailbox owner's name to the channel specified.

Parameters:
[in] chan Channel on which to play the name
[in] mailbox Mailbox number from which to retrieve the recording
[in] context Mailbox context from which to locate the mailbox number
Return values:
0 Name played without interruption
dtmf ASCII value of the DTMF which interrupted playback.
-1 Unable to locate mailbox or hangup occurred.
Since:
1.6.1

Definition at line 356 of file app.c.

References ast_sayname_func.

Referenced by common_exec(), and play_mailbox_owner().

00357 {
00358    if (ast_sayname_func) {
00359       return ast_sayname_func(chan, mailbox, context);
00360    }
00361    return -1;
00362 }

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

Definition at line 1320 of file app.c.

References __ast_app_separate_args().

01321 {
01322    return __ast_app_separate_args(buf, delim, 1, array, arraylen);
01323 }

void ast_close_fds_above_n ( int  n  ) 

Common routine for child processes, to close all fds prior to exec(2).

Parameters:
[in] n starting file descriptor number for closing all higher file descriptors
Since:
1.6.1

Definition at line 2104 of file app.c.

References closefrom().

Referenced by ast_safe_system(), icesencode(), launch_script(), main(), mp3play(), NBScatplay(), send_waveform_to_fd(), spawn_mp3(), spawn_ras(), and vm_check_password_shell().

02105 {
02106    closefrom(n + 1);
02107 }

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,
long *  offsetms 
)

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

Parameters:
chan 
file filename
fwd,rev,stop,pause,restart,skipms,offsetms Before calling this function, set this to be the number of ms to start from the beginning of the file. When the function returns, it will be the number of ms from the beginning where the playback stopped. Pass NULL if you don't care.

Definition at line 561 of file app.c.

References ast_channel::_state, ast_answer(), ast_debug, ast_seekstream(), AST_STATE_UP, ast_stopstream(), ast_streamfile(), ast_tellstream(), ast_verb, ast_waitfordigit(), ast_waitstream_fr(), ast_channel::language, and ast_channel::stream.

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

00565 {
00566    char *breaks = NULL;
00567    char *end = NULL;
00568    int blen = 2;
00569    int res;
00570    long pause_restart_point = 0;
00571    long offset = 0;
00572 
00573    if (offsetms) {
00574       offset = *offsetms * 8; /* XXX Assumes 8kHz */
00575    }
00576 
00577    if (stop) {
00578       blen += strlen(stop);
00579    }
00580    if (suspend) {
00581       blen += strlen(suspend);
00582    }
00583    if (restart) {
00584       blen += strlen(restart);
00585    }
00586 
00587    if (blen > 2) {
00588       breaks = alloca(blen + 1);
00589       breaks[0] = '\0';
00590       if (stop) {
00591          strcat(breaks, stop);
00592       }
00593       if (suspend) {
00594          strcat(breaks, suspend);
00595       }
00596       if (restart) {
00597          strcat(breaks, restart);
00598       }
00599    }
00600    if (chan->_state != AST_STATE_UP) {
00601       res = ast_answer(chan);
00602    }
00603 
00604    if (file) {
00605       if ((end = strchr(file, ':'))) {
00606          if (!strcasecmp(end, ":end")) {
00607             *end = '\0';
00608             end++;
00609          }
00610       }
00611    }
00612 
00613    for (;;) {
00614       ast_stopstream(chan);
00615       res = ast_streamfile(chan, file, chan->language);
00616       if (!res) {
00617          if (pause_restart_point) {
00618             ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
00619             pause_restart_point = 0;
00620          }
00621          else if (end || offset < 0) {
00622             if (offset == -8) {
00623                offset = 0;
00624             }
00625             ast_verb(3, "ControlPlayback seek to offset %ld from end\n", offset);
00626 
00627             ast_seekstream(chan->stream, offset, SEEK_END);
00628             end = NULL;
00629             offset = 0;
00630          } else if (offset) {
00631             ast_verb(3, "ControlPlayback seek to offset %ld\n", offset);
00632             ast_seekstream(chan->stream, offset, SEEK_SET);
00633             offset = 0;
00634          }
00635          res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
00636       }
00637 
00638       if (res < 1) {
00639          break;
00640       }
00641 
00642       /* We go at next loop if we got the restart char */
00643       if (restart && strchr(restart, res)) {
00644          ast_debug(1, "we'll restart the stream here at next loop\n");
00645          pause_restart_point = 0;
00646          continue;
00647       }
00648 
00649       if (suspend && strchr(suspend, res)) {
00650          pause_restart_point = ast_tellstream(chan->stream);
00651          for (;;) {
00652             ast_stopstream(chan);
00653             if (!(res = ast_waitfordigit(chan, 1000))) {
00654                continue;
00655             } else if (res == -1 || strchr(suspend, res) || (stop && strchr(stop, res))) {
00656                break;
00657             }
00658          }
00659          if (res == *suspend) {
00660             res = 0;
00661             continue;
00662          }
00663       }
00664 
00665       if (res == -1) {
00666          break;
00667       }
00668 
00669       /* if we get one of our stop chars, return it to the calling function */
00670       if (stop && strchr(stop, res)) {
00671          break;
00672       }
00673    }
00674 
00675    if (pause_restart_point) {
00676       offset = pause_restart_point;
00677    } else {
00678       if (chan->stream) {
00679          offset = ast_tellstream(chan->stream);
00680       } else {
00681          offset = -8;  /* indicate end of file */
00682       }
00683    }
00684 
00685    if (offsetms) {
00686       *offsetms = offset / 8; /* samples --> ms ... XXX Assumes 8 kHz */
00687    }
00688 
00689    /* If we are returning a digit cast it as char */
00690    if (res > 0 || chan->stream) {
00691       res = (char)res;
00692    }
00693 
00694    ast_stopstream(chan);
00695 
00696    return res;
00697 }

int ast_dtmf_stream ( struct ast_channel chan,
struct ast_channel peer,
const char *  digits,
int  between,
unsigned int  duration 
)

Send DTMF to a channel.

Parameters:
chan The channel that will receive the DTMF frames
peer (optional) Peer channel that will be autoserviced while the primary channel is receiving DTMF
digits This is a string of characters representing the DTMF digits to be sent to the channel. Valid characters are "0123456789*#abcdABCD". Note: You can pass arguments 'f' or 'F', if you want to Flash the channel (if supported by the channel), or 'w' to add a 500 millisecond pause to the DTMF sequence.
between This is the number of milliseconds to wait in between each DTMF digit. If zero milliseconds is specified, then the default value of 100 will be used.
duration This is the duration that each DTMF digit should have.

Definition at line 379 of file app.c.

References ast_autoservice_start(), ast_autoservice_stop(), ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), AST_CONTROL_FLASH, ast_indicate(), ast_log(), ast_opt_transmit_silence, ast_safe_sleep(), ast_senddigit(), ast_waitfor(), and LOG_WARNING.

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

00380 {
00381    const char *ptr;
00382    int res = 0;
00383    struct ast_silence_generator *silgen = NULL;
00384 
00385    if (!between) {
00386       between = 100;
00387    }
00388 
00389    if (peer) {
00390       res = ast_autoservice_start(peer);
00391    }
00392 
00393    if (!res) {
00394       res = ast_waitfor(chan, 100);
00395    }
00396 
00397    /* ast_waitfor will return the number of remaining ms on success */
00398    if (res < 0) {
00399       if (peer) {
00400          ast_autoservice_stop(peer);
00401       }
00402       return res;
00403    }
00404 
00405    if (ast_opt_transmit_silence) {
00406       silgen = ast_channel_start_silence_generator(chan);
00407    }
00408 
00409    for (ptr = digits; *ptr; ptr++) {
00410       if (*ptr == 'w') {
00411          /* 'w' -- wait half a second */
00412          if ((res = ast_safe_sleep(chan, 500))) {
00413             break;
00414          }
00415       } else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
00416          /* Character represents valid DTMF */
00417          if (*ptr == 'f' || *ptr == 'F') {
00418             /* ignore return values if not supported by channel */
00419             ast_indicate(chan, AST_CONTROL_FLASH);
00420          } else {
00421             ast_senddigit(chan, *ptr, duration);
00422          }
00423          /* pause between digits */
00424          if ((res = ast_safe_sleep(chan, between))) {
00425             break;
00426          }
00427       } else {
00428          ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n", *ptr);
00429       }
00430    }
00431 
00432    if (peer) {
00433       /* Stop autoservice on the peer channel, but don't overwrite any error condition
00434          that has occurred previously while acting on the primary channel */
00435       if (ast_autoservice_stop(peer) && !res) {
00436          res = -1;
00437       }
00438    }
00439 
00440    if (silgen) {
00441       ast_channel_stop_silence_generator(chan, silgen);
00442    }
00443 
00444    return res;
00445 }

int ast_get_encoded_char ( const char *  stream,
char *  result,
size_t *  consumed 
)

Decode an encoded control or extended ASCII character.

Parameters:
[in] stream String to decode
[out] result Decoded character
[out] consumed Number of characters used in stream to encode the character
Return values:
-1 Stream is of zero length
0 Success

Definition at line 1989 of file app.c.

References ast_debug, ast_log(), ast_strlen_zero(), and LOG_ERROR.

Referenced by ast_get_encoded_str(), ast_str_get_encoded_str(), cut_internal(), filter(), function_fieldnum_helper(), function_fieldqty_helper(), replace(), shift_pop(), and unshift_push().

01990 {
01991    int i;
01992    *consumed = 1;
01993    *result = 0;
01994    if (ast_strlen_zero(stream)) {
01995       *consumed = 0;
01996       return -1;
01997    }
01998 
01999    if (*stream == '\\') {
02000       *consumed = 2;
02001       switch (*(stream + 1)) {
02002       case 'n':
02003          *result = '\n';
02004          break;
02005       case 'r':
02006          *result = '\r';
02007          break;
02008       case 't':
02009          *result = '\t';
02010          break;
02011       case 'x':
02012          /* Hexadecimal */
02013          if (strchr("0123456789ABCDEFabcdef", *(stream + 2)) && *(stream + 2) != '\0') {
02014             *consumed = 3;
02015             if (*(stream + 2) <= '9') {
02016                *result = *(stream + 2) - '0';
02017             } else if (*(stream + 2) <= 'F') {
02018                *result = *(stream + 2) - 'A' + 10;
02019             } else {
02020                *result = *(stream + 2) - 'a' + 10;
02021             }
02022          } else {
02023             ast_log(LOG_ERROR, "Illegal character '%c' in hexadecimal string\n", *(stream + 2));
02024             return -1;
02025          }
02026 
02027          if (strchr("0123456789ABCDEFabcdef", *(stream + 3)) && *(stream + 3) != '\0') {
02028             *consumed = 4;
02029             *result <<= 4;
02030             if (*(stream + 3) <= '9') {
02031                *result += *(stream + 3) - '0';
02032             } else if (*(stream + 3) <= 'F') {
02033                *result += *(stream + 3) - 'A' + 10;
02034             } else {
02035                *result += *(stream + 3) - 'a' + 10;
02036             }
02037          }
02038          break;
02039       case '0':
02040          /* Octal */
02041          *consumed = 2;
02042          for (i = 2; ; i++) {
02043             if (strchr("01234567", *(stream + i)) && *(stream + i) != '\0') {
02044                (*consumed)++;
02045                ast_debug(5, "result was %d, ", *result);
02046                *result <<= 3;
02047                *result += *(stream + i) - '0';
02048                ast_debug(5, "is now %d\n", *result);
02049             } else {
02050                break;
02051             }
02052          }
02053          break;
02054       default:
02055          *result = *(stream + 1);
02056       }
02057    } else {
02058       *result = *stream;
02059       *consumed = 1;
02060    }
02061    return 0;
02062 }

char* ast_get_encoded_str ( const char *  stream,
char *  result,
size_t  result_len 
)

Decode a stream of encoded control or extended ASCII characters.

Parameters:
[in] stream Encoded string
[out] result Decoded string
[in] result_len Maximum size of the result buffer
Returns:
A pointer to the result string

Definition at line 2064 of file app.c.

References ast_get_encoded_char().

Referenced by listfilter(), mgcp_new(), replace(), sip_addheader(), and sip_new().

02065 {
02066    char *cur = result;
02067    size_t consumed;
02068 
02069    while (cur < result + result_size - 1 && !ast_get_encoded_char(stream, cur, &consumed)) {
02070       cur++;
02071       stream += consumed;
02072    }
02073    *cur = '\0';
02074    return result;
02075 }

void ast_install_vm_functions ( int(*)(const char *mailbox, const char *folder)  has_voicemail_func,
int(*)(const char *mailbox, int *newmsgs, int *oldmsgs)  inboxcount_func,
int(*)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)  inboxcount2_func,
int(*)(const char *context, const char *mailbox, const char *folder)  messagecount_func,
int(*)(struct ast_channel *chan, const char *mailbox, const char *context sayname_func 
)

Set voicemail function callbacks.

Parameters:
[in] has_voicemail_func set function pointer
[in] inboxcount2_func set function pointer
[in] sayname_func set function pointer
[in] inboxcount_func set function pointer
[in] messagecount_func set function pointer
Version:
1.6.1 Added inboxcount2_func, sayname_func

Definition at line 277 of file app.c.

References ast_has_voicemail_func, ast_inboxcount2_func, ast_inboxcount_func, ast_messagecount_func, and ast_sayname_func.

Referenced by load_module().

00282 {
00283    ast_has_voicemail_func = has_voicemail_func;
00284    ast_inboxcount_func = inboxcount_func;
00285    ast_inboxcount2_func = inboxcount2_func;
00286    ast_messagecount_func = messagecount_func;
00287    ast_sayname_func = sayname_func;
00288 }

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 1847 of file app.c.

References ast_ivr_menu_run_internal().

Referenced by skel_exec().

01848 {
01849    int res = ast_ivr_menu_run_internal(chan, menu, cbdata);
01850    /* Hide internal coding */
01851    return res > 0 ? 0 : res;
01852 }

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

Definition at line 1762 of file app.c.

References ast_debug, AST_DIGIT_ANY, ast_log(), AST_MAX_EXTENSION, exten, ivr_dispatch(), LOG_WARNING, maxretries, ast_ivr_option::option, option_exists(), ast_ivr_menu::options, read_newoption(), RES_EXIT, RES_REPEAT, RES_RESTART, RES_UPONE, and ast_ivr_menu::title.

Referenced by ast_ivr_menu_run(), and ivr_dispatch().

01763 {
01764    /* Execute an IVR menu structure */
01765    int res = 0;
01766    int pos = 0;
01767    int retries = 0;
01768    char exten[AST_MAX_EXTENSION] = "s";
01769    if (option_exists(menu, "s") < 0) {
01770       strcpy(exten, "g");
01771       if (option_exists(menu, "g") < 0) {
01772          ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
01773          return -1;
01774       }
01775    }
01776    while (!res) {
01777       while (menu->options[pos].option) {
01778          if (!strcasecmp(menu->options[pos].option, exten)) {
01779             res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
01780             ast_debug(1, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
01781             if (res < 0) {
01782                break;
01783             } else if (res & RES_UPONE) {
01784                return 0;
01785             } else if (res & RES_EXIT) {
01786                return res;
01787             } else if (res & RES_REPEAT) {
01788                int maxretries = res & 0xffff;
01789                if ((res & RES_RESTART) == RES_RESTART) {
01790                   retries = 0;
01791                } else {
01792                   retries++;
01793                }
01794                if (!maxretries) {
01795                   maxretries = 3;
01796                }
01797                if ((maxretries > 0) && (retries >= maxretries)) {
01798                   ast_debug(1, "Max retries %d exceeded\n", maxretries);
01799                   return -2;
01800                } else {
01801                   if (option_exists(menu, "g") > -1) {
01802                      strcpy(exten, "g");
01803                   } else if (option_exists(menu, "s") > -1) {
01804                      strcpy(exten, "s");
01805                   }
01806                }
01807                pos = 0;
01808                continue;
01809             } else if (res && strchr(AST_DIGIT_ANY, res)) {
01810                ast_debug(1, "Got start of extension, %c\n", res);
01811                exten[1] = '\0';
01812                exten[0] = res;
01813                if ((res = read_newoption(chan, menu, exten, sizeof(exten)))) {
01814                   break;
01815                }
01816                if (option_exists(menu, exten) < 0) {
01817                   if (option_exists(menu, "i")) {
01818                      ast_debug(1, "Invalid extension entered, going to 'i'!\n");
01819                      strcpy(exten, "i");
01820                      pos = 0;
01821                      continue;
01822                   } else {
01823                      ast_debug(1, "Aborting on invalid entry, with no 'i' option!\n");
01824                      res = -2;
01825                      break;
01826                   }
01827                } else {
01828                   ast_debug(1, "New existing extension: %s\n", exten);
01829                   pos = 0;
01830                   continue;
01831                }
01832             }
01833          }
01834          pos++;
01835       }
01836       ast_debug(1, "Stopping option '%s', res is %d\n", exten, res);
01837       pos = 0;
01838       if (!strcasecmp(exten, "s")) {
01839          strcpy(exten, "g");
01840       } else {
01841          break;
01842       }
01843    }
01844    return res;
01845 }

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 531 of file app.c.

References ast_activate_generator(), ast_calloc, ast_config_AST_DATA_DIR, ast_copy_string(), ast_log(), ast_strlen_zero(), linear_state::autoclose, errno, linearstream, and LOG_WARNING.

00532 {
00533    struct linear_state *lin;
00534    char tmpf[256];
00535    int res = -1;
00536    int autoclose = 0;
00537    if (fd < 0) {
00538       if (ast_strlen_zero(filename)) {
00539          return -1;
00540       }
00541       autoclose = 1;
00542       if (filename[0] == '/') {
00543          ast_copy_string(tmpf, filename, sizeof(tmpf));
00544       } else {
00545          snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", ast_config_AST_DATA_DIR, "sounds", filename);
00546       }
00547       if ((fd = open(tmpf, O_RDONLY)) < 0) {
00548          ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
00549          return -1;
00550       }
00551    }
00552    if ((lin = ast_calloc(1, sizeof(*lin)))) {
00553       lin->fd = fd;
00554       lin->allowoverride = allowoverride;
00555       lin->autoclose = autoclose;
00556       res = ast_activate_generator(chan, &linearstream, lin);
00557    }
00558    return res;
00559 }

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 1519 of file app.c.

References AST_LOCK_FAILURE, ast_lock_path_flock(), ast_lock_path_lockfile(), AST_LOCK_TYPE_FLOCK, and AST_LOCK_TYPE_LOCKFILE.

Referenced by ast_module_reload(), and vm_lock_path().

01520 {
01521    enum AST_LOCK_RESULT r = AST_LOCK_FAILURE;
01522 
01523    switch (ast_lock_type) {
01524    case AST_LOCK_TYPE_LOCKFILE:
01525       r = ast_lock_path_lockfile(path);
01526       break;
01527    case AST_LOCK_TYPE_FLOCK:
01528       r = ast_lock_path_flock(path);
01529       break;
01530    }
01531 
01532    return r;
01533 }

static enum AST_LOCK_RESULT ast_lock_path_flock ( const char *  path  )  [static]

Definition at line 1399 of file app.c.

References ast_calloc, ast_debug, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, AST_LOCK_FAILURE, AST_LOCK_PATH_NOT_FOUND, AST_LOCK_SUCCESS, AST_LOCK_TIMEOUT, ast_log(), errno, path_lock::fd, path_lock::le, LOG_WARNING, path_lock_destroy(), and strdup.

Referenced by ast_lock_path().

01400 {
01401    char *fs;
01402    int res;
01403    int fd;
01404    time_t start;
01405    struct path_lock *pl;
01406    struct stat st, ost;
01407 
01408    fs = alloca(strlen(path) + 20);
01409 
01410    snprintf(fs, strlen(path) + 19, "%s/lock", path);
01411    if (lstat(fs, &st) == 0) {
01412       if ((st.st_mode & S_IFMT) == S_IFLNK) {
01413          ast_log(LOG_WARNING, "Unable to create lock file "
01414                "'%s': it's already a symbolic link\n",
01415                fs);
01416          return AST_LOCK_FAILURE;
01417       }
01418       if (st.st_nlink > 1) {
01419          ast_log(LOG_WARNING, "Unable to create lock file "
01420                "'%s': %u hard links exist\n",
01421                fs, (unsigned int) st.st_nlink);
01422          return AST_LOCK_FAILURE;
01423       }
01424    }
01425    if ((fd = open(fs, O_WRONLY | O_CREAT, 0600)) < 0) {
01426       ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
01427             fs, strerror(errno));
01428       return AST_LOCK_PATH_NOT_FOUND;
01429    }
01430    if (!(pl = ast_calloc(1, sizeof(*pl)))) {
01431       /* We don't unlink the lock file here, on the possibility that
01432        * someone else created it - better to leave a little mess
01433        * than create a big one by destroying someone else's lock
01434        * and causing something to be corrupted.
01435        */
01436       close(fd);
01437       return AST_LOCK_FAILURE;
01438    }
01439    pl->fd = fd;
01440    pl->path = strdup(path);
01441 
01442    time(&start);
01443    while (
01444       #ifdef SOLARIS
01445       ((res = fcntl(pl->fd, F_SETLK, fcntl(pl->fd, F_GETFL) | O_NONBLOCK)) < 0) &&
01446       #else
01447       ((res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
01448       #endif
01449          (errno == EWOULDBLOCK) &&
01450          (time(NULL) - start < 5))
01451       usleep(1000);
01452    if (res) {
01453       ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n",
01454             path, strerror(errno));
01455       /* No unlinking of lock done, since we tried and failed to
01456        * flock() it.
01457        */
01458       path_lock_destroy(pl);
01459       return AST_LOCK_TIMEOUT;
01460    }
01461 
01462    /* Check for the race where the file is recreated or deleted out from
01463     * underneath us.
01464     */
01465    if (lstat(fs, &st) != 0 && fstat(pl->fd, &ost) != 0 &&
01466          st.st_dev != ost.st_dev &&
01467          st.st_ino != ost.st_ino) {
01468       ast_log(LOG_WARNING, "Unable to create lock file '%s': "
01469             "file changed underneath us\n", fs);
01470       path_lock_destroy(pl);
01471       return AST_LOCK_FAILURE;
01472    }
01473 
01474    /* Success: file created, flocked, and is the one we started with */
01475    AST_LIST_LOCK(&path_lock_list);
01476    AST_LIST_INSERT_TAIL(&path_lock_list, pl, le);
01477    AST_LIST_UNLOCK(&path_lock_list);
01478 
01479    ast_debug(1, "Locked path '%s'\n", path);
01480 
01481    return AST_LOCK_SUCCESS;
01482 }

static enum AST_LOCK_RESULT ast_lock_path_lockfile ( const char *  path  )  [static]

Definition at line 1325 of file app.c.

References ast_debug, AST_FILE_MODE, AST_LOCK_PATH_NOT_FOUND, AST_LOCK_SUCCESS, AST_LOCK_TIMEOUT, ast_log(), ast_random(), errno, LOG_ERROR, and LOG_WARNING.

Referenced by ast_lock_path().

01326 {
01327    char *s;
01328    char *fs;
01329    int res;
01330    int fd;
01331    int lp = strlen(path);
01332    time_t start;
01333 
01334    s = alloca(lp + 10);
01335    fs = alloca(lp + 20);
01336 
01337    snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
01338    fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, AST_FILE_MODE);
01339    if (fd < 0) {
01340       ast_log(LOG_ERROR, "Unable to create lock file '%s': %s\n", path, strerror(errno));
01341       return AST_LOCK_PATH_NOT_FOUND;
01342    }
01343    close(fd);
01344 
01345    snprintf(s, strlen(path) + 9, "%s/.lock", path);
01346    start = time(NULL);
01347    while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) {
01348       sched_yield();
01349    }
01350 
01351    unlink(fs);
01352 
01353    if (res) {
01354       ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
01355       return AST_LOCK_TIMEOUT;
01356    } else {
01357       ast_debug(1, "Locked path '%s'\n", path);
01358       return AST_LOCK_SUCCESS;
01359    }
01360 }

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

Record a file based on input frm a channel. Recording is performed in 'prepend' mode which works a little differently from normal recordings This function will not play a success message due to post-recording control in the application this was added for.

Parameters:
chan the channel being recorded
playfile Filename of sound to play before recording begins
recordfile Filename to save the recording
maxtime_sec Longest possible message length in seconds
fmt string containing all formats to be recorded delimited by '|'
duration pointer to integer for storing length of the recording
sound_duration pointer to integer for storing length of the recording minus all silence
beep whether to play a beep to prompt the recording
silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default
maxsilence_ms length of time in milliseconds which will trigger a timeout from silence, -1 for default.
Return values:
-1 failure or hangup
'S' Recording ended from silence timeout
't' Recording either exceeded maximum duration or the call was ended via DTMF

Definition at line 1056 of file app.c.

References __ast_play_and_record().

Referenced by vm_forwardoptions().

01057 {
01058    return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1);
01059 }

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

Record a file based on input from a channel. Use default accept and cancel DTMF. This function will play "auth-thankyou" upon successful recording.

Parameters:
chan the channel being recorded
playfile Filename of sound to play before recording begins
recordfile Filename to save the recording
maxtime_sec Longest possible message length in seconds
fmt string containing all formats to be recorded delimited by '|'
duration pointer to integer for storing length of the recording
sound_duration pointer to integer for storing length of the recording minus all silence
silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default
maxsilence_ms length of time in milliseconds which will trigger a timeout from silence, -1 for default
path Optional filesystem path to unlock
Return values:
-1 failure or hangup
'S' Recording ended from silence timeout
't' Recording ended from the message exceeding the maximum duration
dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.

Definition at line 1051 of file app.c.

References __ast_play_and_record().

Referenced by app_exec(), ast_record_review(), conf_run(), and setup_privacy_args().

01052 {
01053    return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0);
01054 }

int ast_play_and_record_full ( struct ast_channel chan,
const char *  playfile,
const char *  recordfile,
int  maxtime_sec,
const char *  fmt,
int *  duration,
int *  sound_duration,
int  silencethreshold,
int  maxsilence_ms,
const char *  path,
const char *  acceptdtmf,
const char *  canceldtmf 
)

Record a file based on input from a channel This function will play "auth-thankyou" upon successful recording.

Parameters:
chan the channel being recorded
playfile Filename of sound to play before recording begins
recordfile Filename to save the recording
maxtime_sec Longest possible message length in seconds
fmt string containing all formats to be recorded delimited by '|'
duration pointer to integer for storing length of the recording
sound_duration pointer to integer for storing length of the recording minus all silence
silencethreshold tolerance of noise levels that can be considered silence for the purpose of silence timeout, -1 for default
maxsilence_ms Length of time in milliseconds which will trigger a timeout from silence, -1 for default
path Optional filesystem path to unlock
acceptdtmf Character of DTMF to end and accept the recording
canceldtmf Character of DTMF to end and cancel the recording
Return values:
-1 failure or hangup
'S' Recording ended from silence timeout
't' Recording ended from the message exceeding the maximum duration
dtmfchar Recording ended via the return value's DTMF character for either cancel or accept.

Definition at line 1046 of file app.c.

References __ast_play_and_record(), and S_OR.

Referenced by play_record_review().

01047 {
01048    return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, S_OR(acceptdtmf, default_acceptdtmf), S_OR(canceldtmf, default_canceldtmf), 0);
01049 }

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 699 of file app.c.

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

Referenced by __ast_play_and_record(), advanced_options(), ast_record_review(), ast_say_counted_adjective(), ast_say_counted_noun(), dialout(), forward_message(), get_folder(), get_folder2(), minivm_greet_exec(), play_message_category(), play_message_duration(), play_record_review(), vm_authenticate(), vm_browse_messages_en(), vm_browse_messages_es(), vm_browse_messages_gr(), vm_browse_messages_he(), vm_browse_messages_it(), vm_browse_messages_pt(), vm_browse_messages_vi(), vm_browse_messages_zh(), vm_exec(), vm_execmain(), vm_forwardoptions(), vm_instructions_en(), vm_instructions_zh(), vm_intro(), vm_intro_cs(), vm_intro_de(), vm_intro_en(), vm_intro_es(), vm_intro_fr(), vm_intro_gr(), vm_intro_he(), vm_intro_it(), vm_intro_multilang(), vm_intro_nl(), vm_intro_no(), vm_intro_pl(), vm_intro_pt(), vm_intro_pt_BR(), vm_intro_se(), vm_intro_vi(), vm_intro_zh(), vm_newuser(), vm_options(), vm_play_folder_name(), vm_play_folder_name_gr(), vm_play_folder_name_pl(), vm_play_folder_name_ua(), vm_tempgreeting(), and vmauthenticate().

00700 {
00701    int d = 0;
00702 
00703    ast_test_suite_event_notify("PLAYBACK", "Message: %s", fn);
00704    if ((d = ast_streamfile(chan, fn, chan->language))) {
00705       return d;
00706    }
00707 
00708    d = ast_waitstream(chan, AST_DIGIT_ANY);
00709 
00710    ast_stopstream(chan);
00711 
00712    return d;
00713 }

char* ast_read_textfile ( const char *  filename  ) 

Read a file into asterisk.

Definition at line 1854 of file app.c.

References ast_free, ast_log(), ast_malloc, errno, and LOG_WARNING.

Referenced by readfile_exec().

01855 {
01856    int fd, count = 0, res;
01857    char *output = NULL;
01858    struct stat filesize;
01859 
01860    if (stat(filename, &filesize) == -1) {
01861       ast_log(LOG_WARNING, "Error can't stat %s\n", filename);
01862       return NULL;
01863    }
01864 
01865    count = filesize.st_size + 1;
01866 
01867    if ((fd = open(filename, O_RDONLY)) < 0) {
01868       ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
01869       return NULL;
01870    }
01871 
01872    if ((output = ast_malloc(count))) {
01873       res = read(fd, output, count - 1);
01874       if (res == count - 1) {
01875          output[res] = '\0';
01876       } else {
01877          ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
01878          ast_free(output);
01879          output = NULL;
01880       }
01881    }
01882 
01883    close(fd);
01884 
01885    return output;
01886 }

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 1551 of file app.c.

References AST_DIGIT_ANY, ast_dsp_get_threshold_from_settings(), ast_log(), ast_play_and_record(), ast_play_and_wait(), ast_stream_and_wait(), ast_verb, ast_waitfordigit(), LOG_WARNING, maxsilence, silencethreshold, and THRESHOLD_SILENCE.

Referenced by conf_run().

01552 {
01553    int silencethreshold;
01554    int maxsilence = 0;
01555    int res = 0;
01556    int cmd = 0;
01557    int max_attempts = 3;
01558    int attempts = 0;
01559    int recorded = 0;
01560    int message_exists = 0;
01561    /* Note that urgent and private are for flagging messages as such in the future */
01562 
01563    /* barf if no pointer passed to store duration in */
01564    if (!duration) {
01565       ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
01566       return -1;
01567    }
01568 
01569    cmd = '3';   /* Want to start by recording */
01570 
01571    silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
01572 
01573    while ((cmd >= 0) && (cmd != 't')) {
01574       switch (cmd) {
01575       case '1':
01576          if (!message_exists) {
01577             /* In this case, 1 is to record a message */
01578             cmd = '3';
01579             break;
01580          } else {
01581             ast_stream_and_wait(chan, "vm-msgsaved", "");
01582             cmd = 't';
01583             return res;
01584          }
01585       case '2':
01586          /* Review */
01587          ast_verb(3, "Reviewing the recording\n");
01588          cmd = ast_stream_and_wait(chan, recordfile, AST_DIGIT_ANY);
01589          break;
01590       case '3':
01591          message_exists = 0;
01592          /* Record */
01593          ast_verb(3, "R%secording\n", recorded == 1 ? "e-r" : "");
01594          recorded = 1;
01595          if ((cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, NULL, silencethreshold, maxsilence, path)) == -1) {
01596             /* User has hung up, no options to give */
01597             return cmd;
01598          }
01599          if (cmd == '0') {
01600             break;
01601          } else if (cmd == '*') {
01602             break;
01603          } else {
01604             /* If all is well, a message exists */
01605             message_exists = 1;
01606             cmd = 0;
01607          }
01608          break;
01609       case '4':
01610       case '5':
01611       case '6':
01612       case '7':
01613       case '8':
01614       case '9':
01615       case '*':
01616       case '#':
01617          cmd = ast_play_and_wait(chan, "vm-sorry");
01618          break;
01619       default:
01620          if (message_exists) {
01621             cmd = ast_play_and_wait(chan, "vm-review");
01622          } else {
01623             if (!(cmd = ast_play_and_wait(chan, "vm-torerecord"))) {
01624                cmd = ast_waitfordigit(chan, 600);
01625             }
01626          }
01627 
01628          if (!cmd) {
01629             cmd = ast_waitfordigit(chan, 6000);
01630          }
01631          if (!cmd) {
01632             attempts++;
01633          }
01634          if (attempts > max_attempts) {
01635             cmd = 't';
01636          }
01637       }
01638    }
01639    if (cmd == 't') {
01640       cmd = 0;
01641    }
01642    return cmd;
01643 }

int ast_safe_fork ( int  stop_reaper  ) 

Common routine to safely fork without a chance of a signal handler firing badly in the child.

Parameters:
[in] stop_reaper flag to determine if sigchld handler is replaced or not
Since:
1.6.1

Definition at line 2109 of file app.c.

References ast_calloc, AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_UNLOCK, ast_log(), ast_pthread_create_background, AST_PTHREADT_NULL, ast_replace_sigchld(), errno, zombie::list, LOG_ERROR, LOG_WARNING, and shaun_of_the_dead().

Referenced by filestream_destructor(), icesencode(), launch_script(), mp3play(), NBScatplay(), send_waveform_to_fd(), spawn_mp3(), spawn_ras(), statpost(), and vm_check_password_shell().

02110 {
02111    sigset_t signal_set, old_set;
02112    int pid;
02113 
02114    /* Don't let the default signal handler for children reap our status */
02115    if (stop_reaper) {
02116       ast_replace_sigchld();
02117    }
02118 
02119    sigfillset(&signal_set);
02120    pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
02121 
02122    pid = fork();
02123 
02124    if (pid != 0) {
02125       /* Fork failed or parent */
02126       pthread_sigmask(SIG_SETMASK, &old_set, NULL);
02127       if (!stop_reaper && pid > 0) {
02128          struct zombie *cur = ast_calloc(1, sizeof(*cur));
02129          if (cur) {
02130             cur->pid = pid;
02131             AST_LIST_LOCK(&zombies);
02132             AST_LIST_INSERT_TAIL(&zombies, cur, list);
02133             AST_LIST_UNLOCK(&zombies);
02134             if (shaun_of_the_dead_thread == AST_PTHREADT_NULL) {
02135                if (ast_pthread_create_background(&shaun_of_the_dead_thread, NULL, shaun_of_the_dead, NULL)) {
02136                   ast_log(LOG_ERROR, "Shaun of the Dead wants to kill zombies, but can't?!!\n");
02137                   shaun_of_the_dead_thread = AST_PTHREADT_NULL;
02138                }
02139             }
02140          }
02141       }
02142       return pid;
02143    } else {
02144       /* Child */
02145 #ifdef HAVE_CAP
02146       cap_t cap = cap_from_text("cap_net_admin-eip");
02147 
02148       if (cap_set_proc(cap)) {
02149          ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
02150       }
02151       cap_free(cap);
02152 #endif
02153 
02154       /* Before we unblock our signals, return our trapped signals back to the defaults */
02155       signal(SIGHUP, SIG_DFL);
02156       signal(SIGCHLD, SIG_DFL);
02157       signal(SIGINT, SIG_DFL);
02158       signal(SIGURG, SIG_DFL);
02159       signal(SIGTERM, SIG_DFL);
02160       signal(SIGPIPE, SIG_DFL);
02161       signal(SIGXFSZ, SIG_DFL);
02162 
02163       /* unblock important signal handlers */
02164       if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
02165          ast_log(LOG_WARNING, "unable to unblock signals: %s\n", strerror(errno));
02166          _exit(1);
02167       }
02168 
02169       return pid;
02170    }
02171 }

void ast_safe_fork_cleanup ( void   ) 

Common routine to cleanup after fork'ed process is complete (if reaping was stopped).

Since:
1.6.1

Definition at line 2173 of file app.c.

References ast_unreplace_sigchld().

Referenced by agi_exec_full(), and run_ras().

02174 {
02175    ast_unreplace_sigchld();
02176 }

void ast_set_lock_type ( enum AST_LOCK_TYPE  type  ) 

Set the type of locks used by ast_lock_path().

Parameters:
type the locking type to use

Definition at line 1514 of file app.c.

01515 {
01516    ast_lock_type = type;
01517 }

int ast_str_get_encoded_str ( struct ast_str **  str,
int  maxlen,
const char *  stream 
)

Decode a stream of encoded control or extended ASCII characters.

Definition at line 2077 of file app.c.

References ast_get_encoded_char(), ast_str_buffer(), ast_str_make_space(), ast_str_set(), ast_str_size(), ast_str_update(), and str.

Referenced by sendtext_exec(), and system_exec_helper().

02078 {
02079    char next, *buf;
02080    size_t offset = 0;
02081    size_t consumed;
02082 
02083    if (strchr(stream, '\\')) {
02084       while (!ast_get_encoded_char(stream, &next, &consumed)) {
02085          if (offset + 2 > ast_str_size(*str) && maxlen > -1) {
02086             ast_str_make_space(str, maxlen > 0 ? maxlen : (ast_str_size(*str) + 48) * 2 - 48);
02087          }
02088          if (offset + 2 > ast_str_size(*str)) {
02089             break;
02090          }
02091          buf = ast_str_buffer(*str);
02092          buf[offset++] = next;
02093          stream += consumed;
02094       }
02095       buf = ast_str_buffer(*str);
02096       buf[offset++] = '\0';
02097       ast_str_update(*str);
02098    } else {
02099       ast_str_set(str, maxlen, "%s", stream);
02100    }
02101    return 0;
02102 }

AST_THREADSTORAGE_PUBLIC ( ast_str_thread_global_buf   ) 

void ast_uninstall_vm_functions ( void   ) 

Definition at line 290 of file app.c.

References ast_has_voicemail_func, ast_inboxcount2_func, ast_inboxcount_func, ast_messagecount_func, and ast_sayname_func.

Referenced by unload_module().

00291 {
00292    ast_has_voicemail_func = NULL;
00293    ast_inboxcount_func = NULL;
00294    ast_inboxcount2_func = NULL;
00295    ast_messagecount_func = NULL;
00296    ast_sayname_func = NULL;
00297 }

int ast_unlock_path ( const char *  path  ) 

Unlock a path.

Definition at line 1535 of file app.c.

References AST_LOCK_TYPE_FLOCK, AST_LOCK_TYPE_LOCKFILE, ast_unlock_path_flock(), and ast_unlock_path_lockfile().

Referenced by __ast_play_and_record(), access_counter_file(), ast_module_reload(), copy_message(), count_messages(), open_mailbox(), resequence_mailbox(), and save_to_folder().

01536 {
01537    int r = 0;
01538 
01539    switch (ast_lock_type) {
01540    case AST_LOCK_TYPE_LOCKFILE:
01541       r = ast_unlock_path_lockfile(path);
01542       break;
01543    case AST_LOCK_TYPE_FLOCK:
01544       r = ast_unlock_path_flock(path);
01545       break;
01546    }
01547 
01548    return r;
01549 }

static int ast_unlock_path_flock ( const char *  path  )  [static]

Definition at line 1484 of file app.c.

References AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_log(), path_lock::le, LOG_DEBUG, path_lock::path, and path_lock_destroy().

Referenced by ast_unlock_path().

01485 {
01486    char *s;
01487    struct path_lock *p;
01488 
01489    s = alloca(strlen(path) + 20);
01490 
01491    AST_LIST_LOCK(&path_lock_list);
01492    AST_LIST_TRAVERSE_SAFE_BEGIN(&path_lock_list, p, le) {
01493       if (!strcmp(p->path, path)) {
01494          AST_LIST_REMOVE_CURRENT(le);
01495          break;
01496       }
01497    }
01498    AST_LIST_TRAVERSE_SAFE_END;
01499    AST_LIST_UNLOCK(&path_lock_list);
01500 
01501    if (p) {
01502       snprintf(s, strlen(path) + 19, "%s/lock", path);
01503       unlink(s);
01504       path_lock_destroy(p);
01505       ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01506    } else {
01507       ast_log(LOG_DEBUG, "Failed to unlock path '%s': "
01508             "lock not found\n", path);
01509    }
01510 
01511    return 0;
01512 }

static int ast_unlock_path_lockfile ( const char *  path  )  [static]

Definition at line 1362 of file app.c.

References ast_debug, ast_log(), errno, and LOG_ERROR.

Referenced by ast_unlock_path().

01363 {
01364    char *s;
01365    int res;
01366 
01367    s = alloca(strlen(path) + 10);
01368 
01369    snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01370 
01371    if ((res = unlink(s))) {
01372       ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
01373    } else {
01374       ast_debug(1, "Unlocked path '%s'\n", path);
01375    }
01376 
01377    return res;
01378 }

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

Definition at line 1652 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_stream_and_wait(), ast_waitfordigit(), LOG_NOTICE, ast_channel::pbx, RES_EXIT, RES_REPEAT, RES_RESTART, RES_UPONE, ast_pbx::rtimeoutms, and strsep().

Referenced by ast_ivr_menu_run_internal().

01653 {
01654    int res;
01655    int (*ivr_func)(struct ast_channel *, void *);
01656    char *c;
01657    char *n;
01658 
01659    switch (option->action) {
01660    case AST_ACTION_UPONE:
01661       return RES_UPONE;
01662    case AST_ACTION_EXIT:
01663       return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
01664    case AST_ACTION_REPEAT:
01665       return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
01666    case AST_ACTION_RESTART:
01667       return RES_RESTART ;
01668    case AST_ACTION_NOOP:
01669       return 0;
01670    case AST_ACTION_BACKGROUND:
01671       res = ast_stream_and_wait(chan, (char *)option->adata, AST_DIGIT_ANY);
01672       if (res < 0) {
01673          ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01674          res = 0;
01675       }
01676       return res;
01677    case AST_ACTION_PLAYBACK:
01678       res = ast_stream_and_wait(chan, (char *)option->adata, "");
01679       if (res < 0) {
01680          ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01681          res = 0;
01682       }
01683       return res;
01684    case AST_ACTION_MENU:
01685       if ((res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata)) == -2) {
01686          /* Do not pass entry errors back up, treat as though it was an "UPONE" */
01687          res = 0;
01688       }
01689       return res;
01690    case AST_ACTION_WAITOPTION:
01691       if (!(res = ast_waitfordigit(chan, chan->pbx ? chan->pbx->rtimeoutms : 10000))) {
01692          return 't';
01693       }
01694       return res;
01695    case AST_ACTION_CALLBACK:
01696       ivr_func = option->adata;
01697       res = ivr_func(chan, cbdata);
01698       return res;
01699    case AST_ACTION_TRANSFER:
01700       res = ast_parseable_goto(chan, option->adata);
01701       return 0;
01702    case AST_ACTION_PLAYLIST:
01703    case AST_ACTION_BACKLIST:
01704       res = 0;
01705       c = ast_strdupa(option->adata);
01706       while ((n = strsep(&c, ";"))) {
01707          if ((res = ast_stream_and_wait(chan, n,
01708                (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : ""))) {
01709             break;
01710          }
01711       }
01712       ast_stopstream(chan);
01713       return res;
01714    default:
01715       ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
01716       return 0;
01717    }
01718    return -1;
01719 }

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

Definition at line 498 of file app.c.

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

00499 {
00500    struct linear_state *ls = params;
00501 
00502    if (!params) {
00503       return NULL;
00504    }
00505 
00506    /* In this case, params is already malloc'd */
00507    if (ls->allowoverride) {
00508       ast_set_flag(chan, AST_FLAG_WRITE_INT);
00509    } else {
00510       ast_clear_flag(chan, AST_FLAG_WRITE_INT);
00511    }
00512 
00513    ls->origwfmt = chan->writeformat;
00514 
00515    if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00516       ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
00517       ast_free(ls);
00518       ls = params = NULL;
00519    }
00520 
00521    return params;
00522 }

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

Definition at line 469 of file app.c.

References AST_FORMAT_SLINEAR, AST_FRAME_VOICE, AST_FRIENDLY_OFFSET, ast_log(), ast_write(), f, linear_state::fd, and LOG_WARNING.

00470 {
00471    short buf[2048 + AST_FRIENDLY_OFFSET / 2];
00472    struct linear_state *ls = data;
00473    struct ast_frame f = {
00474       .frametype = AST_FRAME_VOICE,
00475       .subclass.codec = AST_FORMAT_SLINEAR,
00476       .data.ptr = buf + AST_FRIENDLY_OFFSET / 2,
00477       .offset = AST_FRIENDLY_OFFSET,
00478    };
00479    int res;
00480 
00481    len = samples * 2;
00482    if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00483       ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" , len);
00484       len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00485    }
00486    res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
00487    if (res > 0) {
00488       f.datalen = res;
00489       f.samples = res / 2;
00490       ast_write(chan, &f);
00491       if (res == len) {
00492          return 0;
00493       }
00494    }
00495    return -1;
00496 }

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

Definition at line 454 of file app.c.

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

00455 {
00456    struct linear_state *ls = params;
00457 
00458    if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
00459       ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
00460    }
00461 
00462    if (ls->autoclose) {
00463       close(ls->fd);
00464    }
00465 
00466    ast_free(params);
00467 }

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

Definition at line 1721 of file app.c.

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

Referenced by ast_ivr_menu_run_internal().

01722 {
01723    int x;
01724    for (x = 0; menu->options[x].option; x++) {
01725       if (!strcasecmp(menu->options[x].option, option)) {
01726          return x;
01727       }
01728    }
01729    return -1;
01730 }

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

Definition at line 1732 of file app.c.

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

Referenced by read_newoption().

01733 {
01734    int x;
01735    for (x = 0; menu->options[x].option; x++) {
01736       if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
01737             (menu->options[x].option[strlen(option)])) {
01738          return x;
01739       }
01740    }
01741    return -1;
01742 }

static int parse_options ( const struct ast_app_option options,
void *  _flags,
char **  args,
char *  optstr,
int  flaglen 
) [static]

Definition at line 1888 of file app.c.

References ast_app_option::arg_index, ast_clear_flag, ast_copy_string(), AST_FLAGS_ALL, ast_log(), ast_set_flag, ast_set_flag64, ast_flags64::flags, ast_flags::flags, LOG_WARNING, paren, and quote().

Referenced by ast_app_parse_options(), and ast_app_parse_options64().

01889 {
01890    char *s, *arg;
01891    int curarg, res = 0;
01892    unsigned int argloc;
01893    struct ast_flags *flags = _flags;
01894    struct ast_flags64 *flags64 = _flags;
01895 
01896    if (flaglen == 32) {
01897       ast_clear_flag(flags, AST_FLAGS_ALL);
01898    } else {
01899       flags64->flags = 0;
01900    }
01901 
01902    if (!optstr) {
01903       return 0;
01904    }
01905 
01906    s = optstr;
01907    while (*s) {
01908       curarg = *s++ & 0x7f;   /* the array (in app.h) has 128 entries */
01909       argloc = options[curarg].arg_index;
01910       if (*s == '(') {
01911          int paren = 1, quote = 0;
01912          int parsequotes = (s[1] == '"') ? 1 : 0;
01913 
01914          /* Has argument */
01915          arg = ++s;
01916          for (; *s; s++) {
01917             if (*s == '(' && !quote) {
01918                paren++;
01919             } else if (*s == ')' && !quote) {
01920                /* Count parentheses, unless they're within quotes (or backslashed, below) */
01921                paren--;
01922             } else if (*s == '"' && parsequotes) {
01923                /* Leave embedded quotes alone, unless they are the first character */
01924                quote = quote ? 0 : 1;
01925                ast_copy_string(s, s + 1, INT_MAX);
01926                s--;
01927             } else if (*s == '\\') {
01928                if (!quote) {
01929                   /* If a backslash is found outside of quotes, remove it */
01930                   ast_copy_string(s, s + 1, INT_MAX);
01931                } else if (quote && s[1] == '"') {
01932                   /* Backslash for a quote character within quotes, remove the backslash */
01933                   ast_copy_string(s, s + 1, INT_MAX);
01934                } else {
01935                   /* Backslash within quotes, keep both characters */
01936                   s++;
01937                }
01938             }
01939 
01940             if (paren == 0) {
01941                break;
01942             }
01943          }
01944          /* This will find the closing paren we found above, or none, if the string ended before we found one. */
01945          if ((s = strchr(s, ')'))) {
01946             if (argloc) {
01947                args[argloc - 1] = arg;
01948             }
01949             *s++ = '\0';
01950          } else {
01951             ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
01952             res = -1;
01953             break;
01954          }
01955       } else if (argloc) {
01956          args[argloc - 1] = "";
01957       }
01958       if (flaglen == 32) {
01959          ast_set_flag(flags, options[curarg].flag);
01960       } else {
01961          ast_set_flag64(flags64, options[curarg].flag);
01962       }
01963    }
01964 
01965    return res;
01966 }

static void path_lock_destroy ( struct path_lock obj  )  [static]

Definition at line 1388 of file app.c.

References free.

Referenced by ast_lock_path_flock(), and ast_unlock_path_flock().

01389 {
01390    if (obj->fd >= 0) {
01391       close(obj->fd);
01392    }
01393    if (obj->path) {
01394       free(obj->path);
01395    }
01396    free(obj);
01397 }

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

Definition at line 1744 of file app.c.

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

Referenced by ast_ivr_menu_run_internal().

01745 {
01746    int res = 0;
01747    int ms;
01748    while (option_matchmore(menu, exten)) {
01749       ms = chan->pbx ? chan->pbx->dtimeoutms : 5000;
01750       if (strlen(exten) >= maxexten - 1) {
01751          break;
01752       }
01753       if ((res = ast_waitfordigit(chan, ms)) < 1) {
01754          break;
01755       }
01756       exten[strlen(exten) + 1] = '\0';
01757       exten[strlen(exten)] = res;
01758    }
01759    return res > 0 ? 0 : res;
01760 }

static void* shaun_of_the_dead ( void *  data  )  [static]

Definition at line 70 of file app.c.

References ast_free, AST_LIST_EMPTY, AST_LIST_FIRST, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_poll, zombie::list, zombie::pid, and status.

Referenced by ast_safe_fork().

00071 {
00072    struct zombie *cur;
00073    int status;
00074    for (;;) {
00075       if (!AST_LIST_EMPTY(&zombies)) {
00076          /* Don't allow cancellation while we have a lock. */
00077          pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
00078          AST_LIST_LOCK(&zombies);
00079          AST_LIST_TRAVERSE_SAFE_BEGIN(&zombies, cur, list) {
00080             if (waitpid(cur->pid, &status, WNOHANG) != 0) {
00081                AST_LIST_REMOVE_CURRENT(list);
00082                ast_free(cur);
00083             }
00084          }
00085          AST_LIST_TRAVERSE_SAFE_END
00086          AST_LIST_UNLOCK(&zombies);
00087          pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
00088       }
00089       pthread_testcancel();
00090       /* Wait for 60 seconds, without engaging in a busy loop. */
00091       ast_poll(NULL, 0, AST_LIST_FIRST(&zombies) ? 5000 : 60000);
00092    }
00093    return NULL;
00094 }


Variable Documentation

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

Definition at line 271 of file app.c.

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

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

Definition at line 273 of file app.c.

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

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

Definition at line 272 of file app.c.

Referenced by ast_app_inboxcount(), ast_app_inboxcount2(), ast_install_vm_functions(), and ast_uninstall_vm_functions().

enum AST_LOCK_TYPE ast_lock_type = AST_LOCK_TYPE_LOCKFILE [static]

Definition at line 224 of file app.c.

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

Definition at line 275 of file app.c.

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

int(*) ast_sayname_func(struct ast_channel *chan, const char *mailbox, const char *context) = NULL [static]

Definition at line 274 of file app.c.

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

const char default_acceptdtmf[] = "#" [static]

Definition at line 1043 of file app.c.

const char default_canceldtmf[] = "" [static]

Definition at line 1044 of file app.c.

int global_maxsilence = 0 [static]

Definition at line 716 of file app.c.

int global_silence_threshold = 128 [static]

Definition at line 715 of file app.c.

struct ast_generator linearstream [static]

Definition at line 524 of file app.c.

Referenced by ast_linear_stream().

pthread_t shaun_of_the_dead_thread = AST_PTHREADT_NULL [static]

Definition at line 61 of file app.c.


Generated on Mon Mar 19 11:30:31 2012 for Asterisk - The Open Source Telephony Project by  doxygen 1.4.7