Newer
Older
* Asterisk -- An open source telephony toolkit.
* Copyright (C) 1999 - 2005, Digium, Inc.
* Mark Spencer <markster@digium.com>
* See http://www.asterisk.org for more information about
* the Asterisk project. Please do not directly contact
* any of the maintainers of this project for assistance;
* the project provides a web site, mailing lists and IRC
* channels for your use.
*
* This program is free software, distributed under the terms of
* the GNU General Public License Version 2. See the LICENSE file
* at the top of the source tree.
*/
*
* \brief Convenient Application Routines
*
* \author Mark Spencer <markster@digium.com>
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/time.h>
#include <signal.h>
#include <errno.h>
#include <unistd.h>
Kevin P. Fleming
committed
#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"
#define MAX_OTHER_FORMATS 10
This function presents a dialtone and reads an extension into 'collect'
which must be a pointer to a **pre-initialized** array of char having a
size of 'size' suitable for writing to. It will collect no more than the smaller
of 'maxlen' or 'size' minus the original strlen() of collect digits.
\return 0 if extension does not exist, 1 if extension exists
int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
{
struct tone_zone_sound *ts;
int res=0, x=0;
if(!timeout && chan->pbx)
timeout = chan->pbx->dtimeout;
else if(!timeout)
timeout = 5;
ts = ast_get_indication_tone(chan->zone,"dial");
if (ts && ts->data[0])
res = ast_playtones_start(chan, 0, ts->data, 0);
else
ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n");
for (x = strlen(collect); x < maxlen; ) {
res = ast_waitfordigit(chan, timeout);
if (!ast_ignore_pattern(context, collect))
ast_playtones_stop(chan);
if (res < 1)
break;
collect[x++] = res;
if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num)) {
if (collect[x-1] == '#') {
/* Not a valid extension, ending in #, assume the # was to finish dialing */
collect[x-1] = '\0';
}
break;
}
}
if (res >= 0)
res = ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num) ? 1 : 0;
return res;
}
/*! \param timeout set timeout to 0 for "standard" timeouts. Set timeout to -1 for
"ludicrous time" (essentially never times out) */
int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
{
int res,to,fto;
/* XXX Merge with full version? XXX */
if (maxlen)
s[0] = '\0';
if (prompt) {
res = ast_streamfile(c, prompt, c->language);
if (res < 0)
return res;
}
fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
if (timeout > 0)
fto = to = timeout;
if (timeout < 0)
fto = to = 1000000000;
res = ast_readstring(c, s, maxlen, to, fto, "#");
return res;
}
int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
{
int res,to,fto;
if (prompt) {
res = ast_streamfile(c, prompt, c->language);
if (res < 0)
return res;
}
fto = 6000;
to = 2000;
if (timeout > 0)
fto = to = timeout;
if (timeout < 0)
fto = to = 1000000000;
res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
return res;
}
int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
{
int res;
struct ast_filestream *writer;
int rfmt;
struct ast_frame *f;
struct ast_dsp *sildet;
/* Play prompt if requested */
if (prompt) {
res = ast_stream_and_wait(c, prompt, c->language, "");
if (res < 0)
return res;
}
rfmt = c->readformat;
Mark Spencer
committed
res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
return -1;
}
sildet = ast_dsp_new();
if (!sildet) {
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
return -1;
}
writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
if (!writer) {
ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
ast_dsp_free(sildet);
return -1;
}
for(;;) {
if ((res = ast_waitfor(c, 2000)) < 0) {
ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
break;
}
if (res) {
f = ast_read(c);
if (!f) {
ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
break;
}
if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
/* Ended happily with DTMF */
ast_frfree(f);
break;
} else if (f->frametype == AST_FRAME_VOICE) {
ast_dsp_silence(sildet, f, &total);
if (total > silence) {
/* Ended happily with silence */
ast_frfree(f);
break;
}
totalms += f->samples / 8;
if (totalms > maxsec * 1000) {
/* Ended happily with too much stuff */
ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
ast_frfree(f);
break;
}
res = ast_writestream(writer, f);
if (res < 0) {
ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
ast_frfree(f);
break;
}
Mark Spencer
committed
res = ast_set_read_format(c, rfmt);
if (res)
ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
ast_dsp_free(sildet);
ast_closestream(writer);
return 0;
}
static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
static int (*ast_messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
int (*messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs))
{
ast_has_voicemail_func = has_voicemail_func;
ast_messagecount_func = messagecount_func;
}
void ast_uninstall_vm_functions(void)
{
ast_has_voicemail_func = NULL;
ast_messagecount_func = NULL;
}
int ast_app_has_voicemail(const char *mailbox, const char *folder)
if (ast_has_voicemail_func)
return ast_has_voicemail_func(mailbox, folder);
if ((option_verbose > 2) && !warned) {
ast_verbose(VERBOSE_PREFIX_3 "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
{
if (newmsgs)
*newmsgs = 0;
if (oldmsgs)
*oldmsgs = 0;
if (ast_messagecount_func)
return ast_messagecount_func(mailbox, newmsgs, oldmsgs);
if (!warned && (option_verbose > 2)) {
warned++;
ast_verbose(VERBOSE_PREFIX_3 "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const char *digits, int between)
const char *ptr;
struct ast_frame f = {
.frametype = AST_FRAME_DTMF,
.src = "ast_dtmf_stream"
};
if (!res)
res = ast_waitfor(chan, 100);
/* ast_waitfor will return the number of remaining ms on success */
if (res < 0)
return res;
for (ptr = digits; *ptr; ptr++) {
if (*ptr == 'w') {
/* 'w' -- wait half a second */
if ((res = ast_safe_sleep(chan, 500)))
break;
} else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
/* Character represents valid DTMF */
if (*ptr == 'f' || *ptr == 'F') {
/* ignore return values if not supported by channel */
ast_indicate(chan, AST_CONTROL_FLASH);
} else {
if ((res = ast_write(chan, &f)))
break;
/* pause between digits */
if ((res = ast_safe_sleep(chan, between)))
break;
} else
ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
if (peer) {
/* Stop autoservice on the peer channel, but don't overwrite any error condition
that has occurred previously while acting on the primary channel */
if (ast_autoservice_stop(peer) && !res)
res = -1;
}
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
struct linear_state {
int fd;
int autoclose;
int allowoverride;
int origwfmt;
};
static void linear_release(struct ast_channel *chan, void *params)
{
struct linear_state *ls = params;
if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
}
if (ls->autoclose)
close(ls->fd);
free(params);
}
static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
{
struct ast_frame f;
short buf[2048 + AST_FRIENDLY_OFFSET / 2];
struct linear_state *ls = data;
int res;
len = samples * 2;
if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
len = sizeof(buf) - AST_FRIENDLY_OFFSET;
}
memset(&f, 0, sizeof(f));
res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
if (res > 0) {
f.frametype = AST_FRAME_VOICE;
f.subclass = AST_FORMAT_SLINEAR;
f.data = buf + AST_FRIENDLY_OFFSET/2;
f.datalen = res;
f.samples = res / 2;
f.offset = AST_FRIENDLY_OFFSET;
ast_write(chan, &f);
if (res == len)
return 0;
}
return -1;
}
static void *linear_alloc(struct ast_channel *chan, void *params)
{
struct linear_state *ls;
/* In this case, params is already malloc'd */
if (params) {
ls = params;
if (ls->allowoverride)
ast_clear_flag(chan, AST_FLAG_WRITE_INT);
ls->origwfmt = chan->writeformat;
if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
free(ls);
ls = params = NULL;
}
}
return params;
}
static struct ast_generator linearstream =
{
alloc: linear_alloc,
release: linear_release,
generate: linear_generator,
};
int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
{
struct linear_state *lin;
int res = -1;
int autoclose = 0;
if (fd < 0) {
if (ast_strlen_zero(filename))
return -1;
autoclose = 1;
if (filename[0] == '/')
ast_copy_string(tmpf, filename, sizeof(tmpf));
Joshua Colp
committed
snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_DATA_DIR, "sounds", filename);
fd = open(tmpf, O_RDONLY);
if (fd < 0){
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
return -1;
}
}
if ((lin = ast_calloc(1, sizeof(*lin)))) {
lin->fd = fd;
lin->allowoverride = allowoverride;
lin->autoclose = autoclose;
res = ast_activate_generator(chan, &linearstream, lin);
}
return res;
}
Kevin P. Fleming
committed
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)
char *breaks = NULL;
char *end = NULL;
int blen = 2;
int res;
long pause_restart_point = 0;
Mark Spencer
committed
if (stop)
blen += strlen(stop);
if (pause)
blen += strlen(pause);
Kevin P. Fleming
committed
if (restart)
blen += strlen(restart);
Mark Spencer
committed
breaks = alloca(blen + 1);
breaks[0] = '\0';
Kevin P. Fleming
committed
if (stop)
strcat(breaks, stop);
if (pause)
strcat(breaks, pause);
if (restart)
strcat(breaks, restart);
}
Anthony Minessale II
committed
if (chan->_state != AST_STATE_UP)
res = ast_answer(chan);
if (file) {
if ((end = strchr(file,':'))) {
if (!strcasecmp(end, ":end")) {
ast_stopstream(chan);
Anthony Minessale II
committed
res = ast_streamfile(chan, file, chan->language);
if (pause_restart_point) {
ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
pause_restart_point = 0;
Anthony Minessale II
committed
}
else if (end) {
ast_seekstream(chan->stream, 0, SEEK_END);
end = NULL;
};
res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
Anthony Minessale II
committed
}
if (res < 1)
break;
Kevin P. Fleming
committed
/* We go at next loop if we got the restart char */
if (restart && strchr(restart, res)) {
ast_log(LOG_DEBUG, "we'll restart the stream here at next loop\n");
pause_restart_point = 0;
Kevin P. Fleming
committed
continue;
}
if (pause && strchr(pause, res)) {
pause_restart_point = ast_tellstream(chan->stream);
for (;;) {
ast_stopstream(chan);
Anthony Minessale II
committed
res = ast_waitfordigit(chan, 1000);
else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
Anthony Minessale II
committed
break;
}
Anthony Minessale II
committed
res = 0;
continue;
}
}
Anthony Minessale II
committed
break;
/* if we get one of our stop chars, return it to the calling function */
if (stop && strchr(stop, res))
Anthony Minessale II
committed
break;
}
ast_stopstream(chan);
Anthony Minessale II
committed
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
{
int d;
d = ast_streamfile(chan, fn, chan->language);
if (d)
return d;
d = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
return d;
}
static int global_silence_threshold = 128;
static int global_maxsilence = 0;
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)
int d = 0;
Kevin P. Fleming
committed
char *fmts;
char comment[256];
int x, fmtcnt=1, res=-1,outmsg=0;
struct ast_filestream *others[MAX_OTHER_FORMATS];
char *sfmt[MAX_OTHER_FORMATS];
char *stringp=NULL;
time_t start, end;
struct ast_dsp *sildet=NULL; /* silence detector dsp */
int totalsilence = 0;
int rfmt=0;
struct ast_silence_generator *silgen = NULL;
char prependfile[80];
if (silencethreshold < 0)
silencethreshold = global_silence_threshold;
if (maxsilence < 0)
maxsilence = global_maxsilence;
/* barf if no pointer passed to store duration in */
if (duration == NULL) {
ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
return -1;
}
ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
if (playfile || beep) {
if (!beep)
d = ast_play_and_wait(chan, playfile);
if (d > -1)
d = ast_stream_and_wait(chan, "beep", chan->language, "");
if (d < 0)
return -1;
}
if (prepend) {
ast_copy_string(prependfile, recordfile, sizeof(prependfile));
strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
}
fmts = ast_strdupa(fmt);
stringp=fmts;
strsep(&stringp, "|");
ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
sfmt[0] = ast_strdupa(fmts);
while((fmt = strsep(&stringp, "|"))) {
if (fmtcnt > MAX_OTHER_FORMATS - 1) {
ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
break;
}
sfmt[fmtcnt++] = ast_strdupa(fmt);
}
time(&start);
end=start; /* pre-initialize end to be same as start in case we never get into loop */
for (x=0;x<fmtcnt;x++) {
others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
if (!others[x]) {
break;
}
}
if (path)
ast_unlock_path(path);
if (maxsilence > 0) {
sildet = ast_dsp_new(); /* Create the silence detector */
if (!sildet) {
ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
return -1;
}
ast_dsp_set_threshold(sildet, silencethreshold);
rfmt = chan->readformat;
res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
if (res < 0) {
ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
ast_dsp_free(sildet);
return -1;
}
}
if (!prepend) {
/* Request a video update */
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
if (ast_opt_transmit_silence)
silgen = ast_channel_start_silence_generator(chan);
}
if (x == fmtcnt) {
/* Loop forever, writing the packets we read to the writer(s), until
we read a digit or get a hangup */
struct ast_frame *f;
for(;;) {
res = ast_waitfor(chan, 2000);
if (!res) {
ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
/* Try one more time in case of masq */
res = ast_waitfor(chan, 2000);
if (!res) {
ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
res = -1;
}
}
if (res < 0) {
f = NULL;
break;
}
f = ast_read(chan);
if (!f)
break;
if (f->frametype == AST_FRAME_VOICE) {
/* write each format */
for (x=0;x<fmtcnt;x++) {
if (prepend && !others[x])
break;
res = ast_writestream(others[x], f);
}
/* Silence Detection */
if (maxsilence > 0) {
int dspsilence = 0;
ast_dsp_silence(sildet, f, &dspsilence);
if (dspsilence)
totalsilence = dspsilence;
else
totalsilence = 0;
if (totalsilence > maxsilence) {
/* Ended happily with silence */
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
outmsg=2;
break;
}
}
/* Exit on any error */
if (res) {
ast_log(LOG_WARNING, "Error writing frame\n");
break;
}
} else if (f->frametype == AST_FRAME_VIDEO) {
/* Write only once */
ast_writestream(others[0], f);
} else if (f->frametype == AST_FRAME_DTMF) {
if (prepend) {
/* stop recording with any digit */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
res = 't';
outmsg = 2;
break;
}
if (f->subclass == '#') {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
res = '#';
outmsg = 2;
break;
}
if (f->subclass == '0') {
/* Check for a '0' during message recording also, in case caller wants operator */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
res = '0';
outmsg = 0;
break;
}
if (maxtime) {
time(&end);
if (maxtime < (end - start)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
res = 't';
outmsg = 2;
break;
}
}
ast_frfree(f);
}
if (!f) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
res = -1;
outmsg=1;
} else {
ast_frfree(f);
if (end == start) time(&end);
} else {
ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
}
if (!prepend) {
if (silgen)
ast_channel_stop_silence_generator(chan, silgen);
*duration = end - start;
if (!prepend) {
for (x=0;x<fmtcnt;x++) {
if (!others[x])
break;
if (res > 0)
ast_stream_rewind(others[x], totalsilence ? totalsilence-200 : 200);
ast_truncstream(others[x]);
ast_closestream(others[x]);
}
}
if (prepend && outmsg) {
struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
struct ast_frame *fr;
for (x=0;x<fmtcnt;x++) {
snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
if (!others[x] || !realfiles[x])
break;
ast_stream_rewind(others[x], totalsilence ? totalsilence-200 : 200);
ast_truncstream(others[x]);
/* add the original file too */
while ((fr = ast_readframe(realfiles[x]))) {
ast_writestream(others[x],fr);
ast_frfree(fr);
}
ast_closestream(others[x]);
ast_closestream(realfiles[x]);
ast_filerename(prependfile, recordfile, sfmt[x]);
if (option_verbose > 3)
ast_verbose(VERBOSE_PREFIX_4 "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
ast_filedelete(prependfile, sfmt[x]);
}
}
if (rfmt && ast_set_read_format(chan, rfmt)) {
ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
ast_stream_and_wait(chan, "auth-thankyou", chan->language, "");
if (sildet)
ast_dsp_free(sildet);
return res;
}
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)
{
return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, 0, silencethreshold, maxsilence, path, 0);
}
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)
{
return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, beep, silencethreshold, maxsilence, NULL, 1);
}
/* Channel group core functions */
int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
char *grp=NULL, *cat=NULL;
if (!ast_strlen_zero(data)) {
ast_copy_string(tmp, data, sizeof(tmp));
grp = tmp;
cat = strchr(tmp, '@');
if (cat) {
*cat = '\0';
cat++;
}
}
if (!ast_strlen_zero(grp))
ast_copy_string(group, grp, group_max);
else
res = -1;
if (cat)
snprintf(category, category_max, "%s_%s", GROUP_CATEGORY_PREFIX, cat);
else
ast_copy_string(category, GROUP_CATEGORY_PREFIX, category_max);
return res;
}
int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
{
int res=0;
char group[80] = "";
char category[80] = "";
if (!ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
pbx_builtin_setvar_helper(chan, category, group);
} else
res = -1;
return res;
}
int ast_app_group_get_count(const char *group, const char *category)
{
struct ast_channel *chan;
int count = 0;
const char *test;
const char *s;
if (ast_strlen_zero(group))
Kevin P. Fleming
committed
return 0;
s = S_OR(category, GROUP_CATEGORY_PREFIX);
Kevin P. Fleming
committed
ast_copy_string(cat, s, sizeof(cat));
chan = NULL;
while ((chan = ast_channel_walk_locked(chan)) != NULL) {
test = pbx_builtin_getvar_helper(chan, cat);
if (test && !strcasecmp(test, group))
count++;
ast_channel_unlock(chan);
}
return count;
}
int ast_app_group_match_get_count(const char *groupmatch, const char *category)
{
regex_t regexbuf;
struct ast_channel *chan;
int count = 0;
const char *test;
const char *s;
if (ast_strlen_zero(groupmatch))
return 0;
/* if regex compilation fails, return zero matches */
if (regcomp(®exbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
return 0;
s = S_OR(category, GROUP_CATEGORY_PREFIX);
Kevin P. Fleming
committed
ast_copy_string(cat, s, sizeof(cat));
Kevin P. Fleming
committed
chan = NULL;
while ((chan = ast_channel_walk_locked(chan)) != NULL) {
test = pbx_builtin_getvar_helper(chan, cat);
if (test && !regexec(®exbuf, test, 0, NULL, 0))
count++;
ast_channel_unlock(chan);
}
regfree(®exbuf);
return count;
}
unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
int argc;
Kevin P. Fleming
committed
char *scan;
Tilghman Lesher
committed
int paren = 0, quote = 0;
Kevin P. Fleming
committed
if (!buf || !array || !arraylen)
Kevin P. Fleming
committed
memset(array, 0, arraylen * sizeof(*array));
scan = buf;
for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
array[argc] = scan;
for (; *scan; scan++) {
if (*scan == '(')
paren++;
else if (*scan == ')') {
if (paren)
paren--;
Tilghman Lesher
committed
} else if (*scan == '"') {
quote = quote ? 0 : 1;
/* Remove quote character from argument */
memmove(scan, scan + 1, strlen(scan));
scan--;
} else if (*scan == '\\') {
/* Literal character, don't parse */
memmove(scan, scan + 1, strlen(scan));
} else if ((*scan == delim) && !paren && !quote) {
*scan++ = '\0';
break;
}
}
Kevin P. Fleming
committed
if (*scan)
array[argc++] = scan;
Kevin P. Fleming
committed
return argc;
enum AST_LOCK_RESULT ast_lock_path(const char *path)
{
char *s;
char *fs;
int res;
int fd;
int lp = strlen(path);
time_t start;
if (!(s = alloca(lp + 10)) || !(fs = alloca(lp + 20))) {
ast_log(LOG_WARNING, "Out of memory!\n");
Tilghman Lesher
committed
snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
if (fd < 0) {
fprintf(stderr, "Unable to create lock file '%s': %s\n", path, strerror(errno));
return AST_LOCK_PATH_NOT_FOUND;
}
close(fd);
snprintf(s, strlen(path) + 9, "%s/.lock", path);
time(&start);
while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
usleep(1);
ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
return AST_LOCK_TIMEOUT;
} else {
unlink(fs);
ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
return AST_LOCK_SUCCESS;
}
}
int ast_unlock_path(const char *path)
{
char *s;
if (!(s = alloca(strlen(path) + 10)))
return -1;
snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
return unlink(s);
}
int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
{
int silencethreshold = 128;
int maxsilence=0;
int res = 0;
int cmd = 0;
int max_attempts = 3;
int attempts = 0;
int recorded = 0;