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

Go to the source code of this file.
Data Structures | |
| struct | linear_state |
Defines | |
| #define | MAX_OTHER_FORMATS 10 |
| #define | RES_EXIT (1 << 17) |
| #define | RES_REPEAT (1 << 18) |
| #define | RES_RESTART ((1 << 19) | RES_REPEAT) |
| #define | RES_UPONE (1 << 16) |
Functions | |
| static int | __ast_play_and_record (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int beep, int silencethreshold, int maxsilence, const char *path, int prepend, const char *acceptdtmf, const char *canceldtmf) |
| int | ast_app_dtget (struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout) |
| Present a dialtone and collect a certain length extension. | |
| int | ast_app_getdata (struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout) |
| Plays a stream and gets DTMF data from a channel. | |
| int | ast_app_getdata_full (struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd) |
| Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions. | |
| int | ast_app_group_discard (struct ast_channel *chan) |
| int | ast_app_group_get_count (const char *group, const char *category) |
| ast_group_info * | ast_app_group_list_head (void) |
| int | ast_app_group_list_lock (void) |
| int | ast_app_group_list_unlock (void) |
| int | ast_app_group_match_get_count (const char *groupmatch, const char *category) |
| int | ast_app_group_set_channel (struct ast_channel *chan, const char *data) |
| int | ast_app_group_split_group (const char *data, char *group, int group_max, char *category, int category_max) |
| int | ast_app_group_update (struct ast_channel *old, struct ast_channel *new) |
| int | ast_app_has_voicemail (const char *mailbox, const char *folder) |
| int | ast_app_inboxcount (const char *mailbox, int *newmsgs, int *oldmsgs) |
| int | ast_app_messagecount (const char *context, const char *mailbox, const char *folder) |
| void | ast_app_options2str (const struct ast_app_option *options, struct ast_flags *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. | |
| unsigned int | ast_app_separate_args (char *buf, char delim, char **array, int arraylen) |
| Separate a string into arguments in an array. | |
| int | ast_control_streamfile (struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms) |
| int | ast_dtmf_stream (struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between) |
| Send DTMF to a channel. | |
| 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(*messagecount_func)(const char *context, const char *mailbox, const char *folder)) |
| 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) |
| static | AST_LIST_HEAD_STATIC (groups, ast_group_info) |
| enum AST_LOCK_RESULT | ast_lock_path (const char *path) |
| Lock a filesystem path. | |
| int | ast_play_and_prepend (struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int *duration, int beep, int silencethreshold, int maxsilence) |
| int | ast_play_and_record (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path) |
| int | ast_play_and_record_full (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path, const char *acceptdtmf, const char *canceldtmf) |
| int | ast_play_and_wait (struct ast_channel *chan, const char *fn) |
| char * | ast_read_textfile (const char *filename) |
| int | ast_record_review (struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path) |
| void | ast_uninstall_vm_functions (void) |
| int | ast_unlock_path (const char *path) |
| 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 | read_newoption (struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten) |
Variables | |
| static int(*) | ast_has_voicemail_func (const char *mailbox, const char *folder) = NULL |
| static int(*) | ast_inboxcount_func (const char *mailbox, int *newmsgs, int *oldmsgs) = NULL |
| static int(*) | ast_messagecount_func (const char *context, const char *mailbox, const char *folder) = NULL |
| static char | default_acceptdtmf [] = "#" |
| static char | default_canceldtmf [] = "" |
| static int | global_maxsilence = 0 |
| static int | global_silence_threshold = 128 |
| static struct ast_generator | linearstream |
Definition in file app.c.
| #define MAX_OTHER_FORMATS 10 |
| #define RES_EXIT (1 << 17) |
Definition at line 1163 of file app.c.
Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().
| #define RES_REPEAT (1 << 18) |
Definition at line 1164 of file app.c.
Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().
| #define RES_RESTART ((1 << 19) | RES_REPEAT) |
Definition at line 1165 of file app.c.
Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().
| #define RES_UPONE (1 << 16) |
Definition at line 1162 of file app.c.
Referenced by ast_ivr_menu_run_internal(), and ivr_dispatch().
| static int __ast_play_and_record | ( | struct ast_channel * | chan, | |
| const char * | playfile, | |||
| const char * | recordfile, | |||
| int | maxtime, | |||
| const char * | fmt, | |||
| int * | duration, | |||
| int | beep, | |||
| int | silencethreshold, | |||
| int | maxsilence, | |||
| const char * | path, | |||
| int | prepend, | |||
| const char * | acceptdtmf, | |||
| const char * | canceldtmf | |||
| ) | [static] |
Optionally play a sound file or a beep, then record audio and video from the channel.
| 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 milliseconds). | |
| 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). | |
| 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. | |
| acceptdtmf | DTMF digits that will end the recording. | |
| canceldtmf | DTMF digits that will cancel the recording. |
Same logic as above.
Definition at line 504 of file app.c.
References ast_channel_start_silence_generator(), ast_channel_stop_silence_generator(), ast_closestream(), AST_CONTROL_VIDUPDATE, ast_dsp_free(), ast_dsp_new(), ast_dsp_set_threshold(), ast_dsp_silence(), ast_filedelete(), ast_filerename(), AST_FORMAT_SLINEAR, AST_FRAME_DTMF, AST_FRAME_VIDEO, AST_FRAME_VOICE, ast_frfree, ast_getformatname(), ast_indicate(), ast_log(), ast_opt_transmit_silence, ast_play_and_wait(), ast_read(), ast_readfile(), ast_readframe(), ast_set_read_format(), ast_strdupa, ast_stream_and_wait(), ast_stream_rewind(), ast_tellstream(), ast_truncstream(), ast_unlock_path(), ast_verbose(), ast_waitfor(), ast_writefile(), ast_writestream(), f, LOG_DEBUG, LOG_WARNING, MAX_OTHER_FORMATS, option_debug, option_verbose, ast_channel::readformat, strsep(), ast_dsp::totalsilence, VERBOSE_PREFIX_3, and VERBOSE_PREFIX_4.
Referenced by ast_play_and_prepend(), ast_play_and_record(), and ast_play_and_record_full().
00505 { 00506 int d = 0; 00507 char *fmts; 00508 char comment[256]; 00509 int x, fmtcnt = 1, res = -1, outmsg = 0; 00510 struct ast_filestream *others[MAX_OTHER_FORMATS]; 00511 char *sfmt[MAX_OTHER_FORMATS]; 00512 char *stringp = NULL; 00513 time_t start, end; 00514 struct ast_dsp *sildet = NULL; /* silence detector dsp */ 00515 int totalsilence = 0; 00516 int rfmt = 0; 00517 struct ast_silence_generator *silgen = NULL; 00518 char prependfile[80]; 00519 00520 if (silencethreshold < 0) 00521 silencethreshold = global_silence_threshold; 00522 00523 if (maxsilence < 0) 00524 maxsilence = global_maxsilence; 00525 00526 /* barf if no pointer passed to store duration in */ 00527 if (duration == NULL) { 00528 ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n"); 00529 return -1; 00530 } 00531 00532 if (option_debug) 00533 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt); 00534 snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name); 00535 00536 if (playfile || beep) { 00537 if (!beep) 00538 d = ast_play_and_wait(chan, playfile); 00539 if (d > -1) 00540 d = ast_stream_and_wait(chan, "beep", chan->language, ""); 00541 if (d < 0) 00542 return -1; 00543 } 00544 00545 if (prepend) { 00546 ast_copy_string(prependfile, recordfile, sizeof(prependfile)); 00547 strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1); 00548 } 00549 00550 fmts = ast_strdupa(fmt); 00551 00552 stringp = fmts; 00553 strsep(&stringp, "|"); 00554 if (option_debug) 00555 ast_log(LOG_DEBUG, "Recording Formats: sfmts=%s\n", fmts); 00556 sfmt[0] = ast_strdupa(fmts); 00557 00558 while ((fmt = strsep(&stringp, "|"))) { 00559 if (fmtcnt > MAX_OTHER_FORMATS - 1) { 00560 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n"); 00561 break; 00562 } 00563 sfmt[fmtcnt++] = ast_strdupa(fmt); 00564 } 00565 00566 end = start = time(NULL); /* pre-initialize end to be same as start in case we never get into loop */ 00567 for (x = 0; x < fmtcnt; x++) { 00568 others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, 0777); 00569 if (option_verbose > 2) 00570 ast_verbose(VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]); 00571 00572 if (!others[x]) 00573 break; 00574 } 00575 00576 if (path) 00577 ast_unlock_path(path); 00578 00579 if (maxsilence > 0) { 00580 sildet = ast_dsp_new(); /* Create the silence detector */ 00581 if (!sildet) { 00582 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 00583 return -1; 00584 } 00585 ast_dsp_set_threshold(sildet, silencethreshold); 00586 rfmt = chan->readformat; 00587 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR); 00588 if (res < 0) { 00589 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); 00590 ast_dsp_free(sildet); 00591 return -1; 00592 } 00593 } 00594 00595 if (!prepend) { 00596 /* Request a video update */ 00597 ast_indicate(chan, AST_CONTROL_VIDUPDATE); 00598 00599 if (ast_opt_transmit_silence) 00600 silgen = ast_channel_start_silence_generator(chan); 00601 } 00602 00603 if (x == fmtcnt) { 00604 /* Loop forever, writing the packets we read to the writer(s), until 00605 we read a digit or get a hangup */ 00606 struct ast_frame *f; 00607 for (;;) { 00608 res = ast_waitfor(chan, 2000); 00609 if (!res) { 00610 if (option_debug) 00611 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n"); 00612 /* Try one more time in case of masq */ 00613 res = ast_waitfor(chan, 2000); 00614 if (!res) { 00615 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name); 00616 res = -1; 00617 } 00618 } 00619 00620 if (res < 0) { 00621 f = NULL; 00622 break; 00623 } 00624 f = ast_read(chan); 00625 if (!f) 00626 break; 00627 if (f->frametype == AST_FRAME_VOICE) { 00628 /* write each format */ 00629 for (x = 0; x < fmtcnt; x++) { 00630 if (prepend && !others[x]) 00631 break; 00632 res = ast_writestream(others[x], f); 00633 } 00634 00635 /* Silence Detection */ 00636 if (maxsilence > 0) { 00637 int dspsilence = 0; 00638 ast_dsp_silence(sildet, f, &dspsilence); 00639 if (dspsilence) 00640 totalsilence = dspsilence; 00641 else 00642 totalsilence = 0; 00643 00644 if (totalsilence > maxsilence) { 00645 /* Ended happily with silence */ 00646 if (option_verbose > 2) 00647 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000); 00648 res = 'S'; 00649 outmsg = 2; 00650 break; 00651 } 00652 } 00653 /* Exit on any error */ 00654 if (res) { 00655 ast_log(LOG_WARNING, "Error writing frame\n"); 00656 break; 00657 } 00658 } else if (f->frametype == AST_FRAME_VIDEO) { 00659 /* Write only once */ 00660 ast_writestream(others[0], f); 00661 } else if (f->frametype == AST_FRAME_DTMF) { 00662 if (prepend) { 00663 /* stop recording with any digit */ 00664 if (option_verbose > 2) 00665 ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); 00666 res = 't'; 00667 outmsg = 2; 00668 break; 00669 } 00670 if (strchr(acceptdtmf, f->subclass)) { 00671 if (option_verbose > 2) 00672 ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass); 00673 res = f->subclass; 00674 outmsg = 2; 00675 break; 00676 } 00677 if (strchr(canceldtmf, f->subclass)) { 00678 if (option_verbose > 2) 00679 ast_verbose(VERBOSE_PREFIX_3 "User cancelled message by pressing %c\n", f->subclass); 00680 res = f->subclass; 00681 outmsg = 0; 00682 break; 00683 } 00684 } 00685 if (maxtime) { 00686 end = time(NULL); 00687 if (maxtime < (end - start)) { 00688 if (option_verbose > 2) 00689 ast_verbose(VERBOSE_PREFIX_3 "Took too long, cutting it short...\n"); 00690 res = 't'; 00691 outmsg = 2; 00692 break; 00693 } 00694 } 00695 ast_frfree(f); 00696 } 00697 if (!f) { 00698 if (option_verbose > 2) 00699 ast_verbose(VERBOSE_PREFIX_3 "User hung up\n"); 00700 res = -1; 00701 outmsg = 1; 00702 } else { 00703 ast_frfree(f); 00704 } 00705 } else { 00706 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]); 00707 } 00708 00709 if (!prepend) { 00710 if (silgen) 00711 ast_channel_stop_silence_generator(chan, silgen); 00712 } 00713 00714 /*!\note 00715 * Instead of asking how much time passed (end - start), calculate the number 00716 * of seconds of audio which actually went into the file. This fixes a 00717 * problem where audio is stopped up on the network and never gets to us. 00718 * 00719 * Note that we still want to use the number of seconds passed for the max 00720 * message, otherwise we could get a situation where this stream is never 00721 * closed (which would create a resource leak). 00722 */ 00723 *duration = others[0] ? ast_tellstream(others[0]) / 8000 : 0; 00724 00725 if (!prepend) { 00726 for (x = 0; x < fmtcnt; x++) { 00727 if (!others[x]) 00728 break; 00729 /*!\note 00730 * If we ended with silence, trim all but the first 200ms of silence 00731 * off the recording. However, if we ended with '#', we don't want 00732 * to trim ANY part of the recording. 00733 */ 00734 if (res > 0 && totalsilence) 00735 ast_stream_rewind(others[x], totalsilence - 200); 00736 ast_truncstream(others[x]); 00737 ast_closestream(others[x]); 00738 } 00739 } 00740 00741 if (prepend && outmsg) { 00742 struct ast_filestream *realfiles[MAX_OTHER_FORMATS]; 00743 struct ast_frame *fr; 00744 00745 for (x = 0; x < fmtcnt; x++) { 00746 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]); 00747 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0); 00748 if (!others[x] || !realfiles[x]) 00749 break; 00750 /*!\note Same logic as above. */ 00751 if (totalsilence) 00752 ast_stream_rewind(others[x], totalsilence - 200); 00753 ast_truncstream(others[x]); 00754 /* add the original file too */ 00755 while ((fr = ast_readframe(realfiles[x]))) { 00756 ast_writestream(others[x], fr); 00757 ast_frfree(fr); 00758 } 00759 ast_closestream(others[x]); 00760 ast_closestream(realfiles[x]); 00761 ast_filerename(prependfile, recordfile, sfmt[x]); 00762 if (option_verbose > 3) 00763 ast_verbose(VERBOSE_PREFIX_4 "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile); 00764 ast_filedelete(prependfile, sfmt[x]); 00765 } 00766 } 00767 if (rfmt && ast_set_read_format(chan, rfmt)) { 00768 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name); 00769 } 00770 if (outmsg == 2) { 00771 ast_stream_and_wait(chan, "auth-thankyou", chan->language, ""); 00772 } 00773 if (sildet) 00774 ast_dsp_free(sildet); 00775 return res; 00776 }
| 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.
Definition at line 65 of file app.c.
References ast_exists_extension(), ast_get_indication_tone(), ast_ignore_pattern(), ast_log(), ast_matchmore_extension(), ast_playtones_start(), ast_playtones_stop(), ast_waitfordigit(), ast_channel::cid, ast_callerid::cid_num, ind_tone_zone_sound::data, ast_pbx::dtimeout, LOG_NOTICE, ast_channel::pbx, and ast_channel::zone.
Referenced by builtin_atxfer(), and builtin_blindtransfer().
00066 { 00067 struct ind_tone_zone_sound *ts; 00068 int res=0, x=0; 00069 00070 if (maxlen > size) 00071 maxlen = size; 00072 00073 if (!timeout && chan->pbx) 00074 timeout = chan->pbx->dtimeout; 00075 else if (!timeout) 00076 timeout = 5; 00077 00078 ts = ast_get_indication_tone(chan->zone,"dial"); 00079 if (ts && ts->data[0]) 00080 res = ast_playtones_start(chan, 0, ts->data, 0); 00081 else 00082 ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n"); 00083 00084 for (x = strlen(collect); x < maxlen; ) { 00085 res = ast_waitfordigit(chan, timeout); 00086 if (!ast_ignore_pattern(context, collect)) 00087 ast_playtones_stop(chan); 00088 if (res < 1) 00089 break; 00090 if (res == '#') 00091 break; 00092 collect[x++] = res; 00093 if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num)) 00094 break; 00095 } 00096 if (res >= 0) 00097 res = ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num) ? 1 : 0; 00098 return res; 00099 }
| int ast_app_getdata | ( | struct ast_channel * | c, | |
| char * | prompt, | |||
| char * | s, | |||
| int | maxlen, | |||
| int | timeout | |||
| ) |
Plays a stream and gets DTMF data from a channel.
| 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 107 of file app.c.
References ast_readstring(), ast_streamfile(), ast_pbx::dtimeout, ast_channel::pbx, and ast_pbx::rtimeout.
Referenced by __login_exec(), auth_exec(), conf_exec(), dictate_exec(), exec(), find_conf(), read_exec(), testclient_exec(), testserver_exec(), and vm_exec().
00108 { 00109 int res,to,fto; 00110 /* XXX Merge with full version? XXX */ 00111 if (maxlen) 00112 s[0] = '\0'; 00113 if (prompt) { 00114 res = ast_streamfile(c, prompt, c->language); 00115 if (res < 0) 00116 return res; 00117 } 00118 fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000; 00119 to = c->pbx ? c->pbx->dtimeout * 1000 : 2000; 00120 00121 if (timeout > 0) 00122 fto = to = timeout; 00123 if (timeout < 0) 00124 fto = to = 1000000000; 00125 res = ast_readstring(c, s, maxlen, to, fto, "#"); 00126 return res; 00127 }
| int ast_app_getdata_full | ( | struct ast_channel * | c, | |
| char * | prompt, | |||
| char * | s, | |||
| int | maxlen, | |||
| int | timeout, | |||
| int | audiofd, | |||
| int | ctrlfd | |||
| ) |
Full version with audiofd and controlfd. NOTE: returns '2' on ctrlfd available, not '1' like other full functions.
Definition at line 130 of file app.c.
References ast_readstring_full(), and ast_streamfile().
Referenced by handle_getdata().
00131 { 00132 int res, to, fto; 00133 if (prompt) { 00134 res = ast_streamfile(c, prompt, c->language); 00135 if (res < 0) 00136 return res; 00137 } 00138 fto = 6000; 00139 to = 2000; 00140 if (timeout > 0) 00141 fto = to = timeout; 00142 if (timeout < 0) 00143 fto = to = 1000000000; 00144 res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd); 00145 return res; 00146 }
| int ast_app_group_discard | ( | struct ast_channel * | chan | ) |
Discard all group counting for a channel
Definition at line 927 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_group_info::chan, and free.
Referenced by ast_channel_free().
00928 { 00929 struct ast_group_info *gi = NULL; 00930 00931 AST_LIST_LOCK(&groups); 00932 AST_LIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) { 00933 if (gi->chan == chan) { 00934 AST_LIST_REMOVE_CURRENT(&groups, list); 00935 free(gi); 00936 } 00937 } 00938 AST_LIST_TRAVERSE_SAFE_END 00939 AST_LIST_UNLOCK(&groups); 00940 00941 return 0; 00942 }
| 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 870 of file app.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_group_info::category, and ast_group_info::group.
Referenced by group_count_function_read().
00871 { 00872 struct ast_group_info *gi = NULL; 00873 int count = 0; 00874 00875 if (ast_strlen_zero(group)) 00876 return 0; 00877 00878 AST_LIST_LOCK(&groups); 00879 AST_LIST_TRAVERSE(&groups, gi, list) { 00880 if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) 00881 count++; 00882 } 00883 AST_LIST_UNLOCK(&groups); 00884 00885 return count; 00886 }
| struct ast_group_info* ast_app_group_list_head | ( | void | ) |
Get the head of the group count list
Definition at line 949 of file app.c.
References AST_LIST_FIRST.
Referenced by group_count_function_read(), group_function_read(), group_list_function_read(), and group_show_channels().
00950 { 00951 return AST_LIST_FIRST(&groups); 00952 }
| int ast_app_group_list_lock | ( | void | ) |
Lock the group count list
Definition at line 944 of file app.c.
References AST_LIST_LOCK.
Referenced by group_count_function_read(), group_function_read(), group_list_function_read(), and group_show_channels().
00945 { 00946 return AST_LIST_LOCK(&groups); 00947 }
| int ast_app_group_list_unlock | ( | void | ) |
Unlock the group count list
Definition at line 954 of file app.c.
References AST_LIST_UNLOCK.
Referenced by group_count_function_read(), group_function_read(), group_list_function_read(), and group_show_channels().
00955 { 00956 return AST_LIST_UNLOCK(&groups); 00957 }
| 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 888 of file app.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, ast_strlen_zero(), ast_group_info::category, and ast_group_info::group.
Referenced by group_match_count_function_read().
00889 { 00890 struct ast_group_info *gi = NULL; 00891 regex_t regexbuf; 00892 int count = 0; 00893 00894 if (ast_strlen_zero(groupmatch)) 00895 return 0; 00896 00897 /* if regex compilation fails, return zero matches */ 00898 if (regcomp(®exbuf, groupmatch, REG_EXTENDED | REG_NOSUB)) 00899 return 0; 00900 00901 AST_LIST_LOCK(&groups); 00902 AST_LIST_TRAVERSE(&groups, gi, list) { 00903 if (!regexec(®exbuf, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) 00904 count++; 00905 } 00906 AST_LIST_UNLOCK(&groups); 00907 00908 regfree(®exbuf); 00909 00910 return count; 00911 }
| 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 825 of file app.c.
References ast_app_group_split_group(), AST_LIST_INSERT_TAIL, AST_LIST_LOCK, AST_LIST_REMOVE_CURRENT, AST_LIST_TRAVERSE_SAFE_BEGIN, AST_LIST_TRAVERSE_SAFE_END, AST_LIST_UNLOCK, ast_strlen_zero(), calloc, ast_group_info::category, ast_group_info::chan, free, group, ast_group_info::group, and len.
Referenced by group_function_write().
00826 { 00827 int res = 0; 00828 char group[80] = "", category[80] = ""; 00829 struct ast_group_info *gi = NULL; 00830 size_t len = 0; 00831 00832 if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) 00833 return -1; 00834 00835 /* Calculate memory we will need if this is new */ 00836 len = sizeof(*gi) + strlen(group) + 1; 00837 if (!ast_strlen_zero(category)) 00838 len += strlen(category) + 1; 00839 00840 AST_LIST_LOCK(&groups); 00841 AST_LIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) { 00842 if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) { 00843 AST_LIST_REMOVE_CURRENT(&groups, list); 00844 free(gi); 00845 break; 00846 } 00847 } 00848 AST_LIST_TRAVERSE_SAFE_END 00849 00850 if (ast_strlen_zero(group)) { 00851 /* Enable unsetting the group */ 00852 } else if ((gi = calloc(1, len))) { 00853 gi->chan = chan; 00854 gi->group = (char *) gi + sizeof(*gi); 00855 strcpy(gi->group, group); 00856 if (!ast_strlen_zero(category)) { 00857 gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1; 00858 strcpy(gi->category, category); 00859 } 00860 AST_LIST_INSERT_TAIL(&groups, gi, list); 00861 } else { 00862 res = -1; 00863 } 00864 00865 AST_LIST_UNLOCK(&groups); 00866 00867 return res; 00868 }
| 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 798 of file app.c.
References ast_strlen_zero().
Referenced by ast_app_group_set_channel(), group_count_function_read(), and group_match_count_function_read().
00799 { 00800 int res=0; 00801 char tmp[256]; 00802 char *grp=NULL, *cat=NULL; 00803 00804 if (!ast_strlen_zero(data)) { 00805 ast_copy_string(tmp, data, sizeof(tmp)); 00806 grp = tmp; 00807 cat = strchr(tmp, '@'); 00808 if (cat) { 00809 *cat = '\0'; 00810 cat++; 00811 } 00812 } 00813 00814 if (!ast_strlen_zero(grp)) 00815 ast_copy_string(group, grp, group_max); 00816 else 00817 *group = '\0'; 00818 00819 if (!ast_strlen_zero(cat)) 00820 ast_copy_string(category, cat, category_max); 00821 00822 return res; 00823 }
| int ast_app_group_update | ( | struct ast_channel * | oldchan, | |
| struct ast_channel * | newchan | |||
| ) |
Update all group counting for a channel to a new one
Definition at line 913 of file app.c.
References AST_LIST_LOCK, AST_LIST_TRAVERSE, AST_LIST_UNLOCK, and ast_group_info::chan.
Referenced by ast_do_masquerade().
00914 { 00915 struct ast_group_info *gi = NULL; 00916 00917 AST_LIST_LOCK(&groups); 00918 AST_LIST_TRAVERSE(&groups, gi, list) { 00919 if (gi->chan == old) 00920 gi->chan = new; 00921 } 00922 AST_LIST_UNLOCK(&groups); 00923 00924 return 0; 00925 }
| int ast_app_has_voicemail | ( | const char * | mailbox, | |
| const char * | folder | |||
| ) |
Determine if a given mailbox has any voicemail
Definition at line 168 of file app.c.
References ast_has_voicemail_func, ast_verbose(), option_verbose, and VERBOSE_PREFIX_3.
Referenced by action_mailboxstatus(), has_voicemail(), notify_new_message(), play_dialtone(), poll_mailbox(), and run_externnotify().
00169 { 00170 static int warned = 0; 00171 if (ast_has_voicemail_func) 00172 return ast_has_voicemail_func(mailbox, folder); 00173 00174 if ((option_verbose > 2) && !warned) { 00175 ast_verbose(VERBOSE_PREFIX_3 "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX"); 00176 warned++; 00177 } 00178 return 0; 00179 }
| int ast_app_inboxcount | ( | const char * | mailbox, | |
| int * | newmsgs, | |||
| int * | oldmsgs | |||
| ) |
Determine number of new/old messages in a mailbox
Definition at line 182 of file app.c.
References ast_inboxcount_func, ast_verbose(), option_verbose, and VERBOSE_PREFIX_3.
Referenced by action_mailboxcount(), notify_new_message(), sip_send_mwi_to_peer(), and update_registry().
00183 { 00184 static int warned = 0; 00185 if (newmsgs) 00186 *newmsgs = 0; 00187 if (oldmsgs) 00188 *oldmsgs = 0; 00189 if (ast_inboxcount_func) 00190 return ast_inboxcount_func(mailbox, newmsgs, oldmsgs); 00191 00192 if (!warned && (option_verbose > 2)) { 00193 warned++; 00194 ast_verbose(VERBOSE_PREFIX_3 "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox); 00195 } 00196 00197 return 0; 00198 }
| int ast_app_messagecount | ( | const char * | context, | |
| const char * | mailbox, | |||
| const char * | folder | |||
| ) |
Determine number of messages in a given mailbox and folder
Definition at line 200 of f