|
|
@ -78,8 +78,9 @@ int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect,
|
|
|
|
struct ast_tone_zone_sound *ts;
|
|
|
|
struct ast_tone_zone_sound *ts;
|
|
|
|
int res = 0, x = 0;
|
|
|
|
int res = 0, x = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (maxlen > size)
|
|
|
|
if (maxlen > size) {
|
|
|
|
maxlen = size;
|
|
|
|
maxlen = size;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!timeout && chan->pbx) {
|
|
|
|
if (!timeout && chan->pbx) {
|
|
|
|
timeout = chan->pbx->dtimeoutms / 1000.0;
|
|
|
|
timeout = chan->pbx->dtimeoutms / 1000.0;
|
|
|
@ -96,19 +97,24 @@ int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect,
|
|
|
|
|
|
|
|
|
|
|
|
for (x = strlen(collect); x < maxlen; ) {
|
|
|
|
for (x = strlen(collect); x < maxlen; ) {
|
|
|
|
res = ast_waitfordigit(chan, timeout);
|
|
|
|
res = ast_waitfordigit(chan, timeout);
|
|
|
|
if (!ast_ignore_pattern(context, collect))
|
|
|
|
if (!ast_ignore_pattern(context, collect)) {
|
|
|
|
ast_playtones_stop(chan);
|
|
|
|
ast_playtones_stop(chan);
|
|
|
|
if (res < 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res < 1) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
if (res == '#')
|
|
|
|
}
|
|
|
|
|
|
|
|
if (res == '#') {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
collect[x++] = res;
|
|
|
|
collect[x++] = res;
|
|
|
|
if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num))
|
|
|
|
if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num)) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (res >= 0)
|
|
|
|
if (res >= 0) {
|
|
|
|
res = ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num) ? 1 : 0;
|
|
|
|
res = ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num) ? 1 : 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -146,14 +152,16 @@ enum ast_getdata_result ast_app_getdata(struct ast_channel *c, const char *promp
|
|
|
|
fto = c->pbx ? c->pbx->rtimeoutms : 6000;
|
|
|
|
fto = c->pbx ? c->pbx->rtimeoutms : 6000;
|
|
|
|
to = c->pbx ? c->pbx->dtimeoutms : 2000;
|
|
|
|
to = c->pbx ? c->pbx->dtimeoutms : 2000;
|
|
|
|
|
|
|
|
|
|
|
|
if (timeout > 0)
|
|
|
|
if (timeout > 0) {
|
|
|
|
fto = to = timeout;
|
|
|
|
fto = to = timeout;
|
|
|
|
if (timeout < 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout < 0) {
|
|
|
|
fto = to = 1000000000;
|
|
|
|
fto = to = 1000000000;
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
/* there is more than one prompt, so
|
|
|
|
/* there is more than one prompt, so
|
|
|
|
get rid of the long timeout between
|
|
|
|
* get rid of the long timeout between
|
|
|
|
prompts, and make it 50ms */
|
|
|
|
* prompts, and make it 50ms */
|
|
|
|
fto = 50;
|
|
|
|
fto = 50;
|
|
|
|
to = c->pbx ? c->pbx->dtimeoutms : 2000;
|
|
|
|
to = c->pbx ? c->pbx->dtimeoutms : 2000;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -178,14 +186,17 @@ int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxle
|
|
|
|
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(prompt)) {
|
|
|
|
if (!ast_strlen_zero(prompt)) {
|
|
|
|
res = ast_streamfile(c, prompt, c->language);
|
|
|
|
res = ast_streamfile(c, prompt, c->language);
|
|
|
|
if (res < 0)
|
|
|
|
if (res < 0) {
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (timeout > 0)
|
|
|
|
if (timeout > 0) {
|
|
|
|
fto = to = timeout;
|
|
|
|
fto = to = timeout;
|
|
|
|
if (timeout < 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (timeout < 0) {
|
|
|
|
fto = to = 1000000000;
|
|
|
|
fto = to = 1000000000;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
|
|
|
|
res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
|
|
|
|
|
|
|
|
|
|
|
@ -223,12 +234,12 @@ void ast_uninstall_vm_functions(void)
|
|
|
|
int ast_app_has_voicemail(const char *mailbox, const char *folder)
|
|
|
|
int ast_app_has_voicemail(const char *mailbox, const char *folder)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
static int warned = 0;
|
|
|
|
static int warned = 0;
|
|
|
|
if (ast_has_voicemail_func)
|
|
|
|
if (ast_has_voicemail_func) {
|
|
|
|
return ast_has_voicemail_func(mailbox, folder);
|
|
|
|
return ast_has_voicemail_func(mailbox, folder);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!warned) {
|
|
|
|
if (warned++ % 10 == 0) {
|
|
|
|
ast_verb(3, "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
|
|
|
|
ast_verb(3, "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
|
|
|
|
warned++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -247,8 +258,7 @@ int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
|
|
|
|
return ast_inboxcount_func(mailbox, newmsgs, oldmsgs);
|
|
|
|
return ast_inboxcount_func(mailbox, newmsgs, oldmsgs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!warned) {
|
|
|
|
if (warned++ % 10 == 0) {
|
|
|
|
warned++;
|
|
|
|
|
|
|
|
ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
|
|
|
|
ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -271,8 +281,7 @@ int ast_app_inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int
|
|
|
|
return ast_inboxcount2_func(mailbox, urgentmsgs, newmsgs, oldmsgs);
|
|
|
|
return ast_inboxcount2_func(mailbox, urgentmsgs, newmsgs, oldmsgs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!warned) {
|
|
|
|
if (warned++ % 10 == 0) {
|
|
|
|
warned++;
|
|
|
|
|
|
|
|
ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
|
|
|
|
ast_verb(3, "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -281,16 +290,18 @@ int ast_app_inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int
|
|
|
|
|
|
|
|
|
|
|
|
int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
|
|
|
|
int ast_app_sayname(struct ast_channel *chan, const char *mailbox, const char *context)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (ast_sayname_func)
|
|
|
|
if (ast_sayname_func) {
|
|
|
|
return ast_sayname_func(chan, mailbox, context);
|
|
|
|
return ast_sayname_func(chan, mailbox, context);
|
|
|
|
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int ast_app_messagecount(const char *context, const char *mailbox, const char *folder)
|
|
|
|
int ast_app_messagecount(const char *context, const char *mailbox, const char *folder)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
static int warned = 0;
|
|
|
|
static int warned = 0;
|
|
|
|
if (ast_messagecount_func)
|
|
|
|
if (ast_messagecount_func) {
|
|
|
|
return ast_messagecount_func(context, mailbox, folder);
|
|
|
|
return ast_messagecount_func(context, mailbox, folder);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!warned) {
|
|
|
|
if (!warned) {
|
|
|
|
warned++;
|
|
|
|
warned++;
|
|
|
@ -306,14 +317,17 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
|
|
|
|
int res = 0;
|
|
|
|
int res = 0;
|
|
|
|
struct ast_silence_generator *silgen = NULL;
|
|
|
|
struct ast_silence_generator *silgen = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
if (!between)
|
|
|
|
if (!between) {
|
|
|
|
between = 100;
|
|
|
|
between = 100;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (peer)
|
|
|
|
if (peer) {
|
|
|
|
res = ast_autoservice_start(peer);
|
|
|
|
res = ast_autoservice_start(peer);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!res)
|
|
|
|
if (!res) {
|
|
|
|
res = ast_waitfor(chan, 100);
|
|
|
|
res = ast_waitfor(chan, 100);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ast_waitfor will return the number of remaining ms on success */
|
|
|
|
/* ast_waitfor will return the number of remaining ms on success */
|
|
|
|
if (res < 0) {
|
|
|
|
if (res < 0) {
|
|
|
@ -330,27 +344,32 @@ int ast_dtmf_stream(struct ast_channel *chan, struct ast_channel *peer, const ch
|
|
|
|
for (ptr = digits; *ptr; ptr++) {
|
|
|
|
for (ptr = digits; *ptr; ptr++) {
|
|
|
|
if (*ptr == 'w') {
|
|
|
|
if (*ptr == 'w') {
|
|
|
|
/* 'w' -- wait half a second */
|
|
|
|
/* 'w' -- wait half a second */
|
|
|
|
if ((res = ast_safe_sleep(chan, 500)))
|
|
|
|
if ((res = ast_safe_sleep(chan, 500))) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
} else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
|
|
|
|
} else if (strchr("0123456789*#abcdfABCDF", *ptr)) {
|
|
|
|
/* Character represents valid DTMF */
|
|
|
|
/* Character represents valid DTMF */
|
|
|
|
if (*ptr == 'f' || *ptr == 'F') {
|
|
|
|
if (*ptr == 'f' || *ptr == 'F') {
|
|
|
|
/* ignore return values if not supported by channel */
|
|
|
|
/* ignore return values if not supported by channel */
|
|
|
|
ast_indicate(chan, AST_CONTROL_FLASH);
|
|
|
|
ast_indicate(chan, AST_CONTROL_FLASH);
|
|
|
|
} else
|
|
|
|
} else {
|
|
|
|
ast_senddigit(chan, *ptr, duration);
|
|
|
|
ast_senddigit(chan, *ptr, duration);
|
|
|
|
|
|
|
|
}
|
|
|
|
/* pause between digits */
|
|
|
|
/* pause between digits */
|
|
|
|
if ((res = ast_safe_sleep(chan, between)))
|
|
|
|
if ((res = ast_safe_sleep(chan, between))) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
} else
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n", *ptr);
|
|
|
|
ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n", *ptr);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (peer) {
|
|
|
|
if (peer) {
|
|
|
|
/* Stop autoservice on the peer channel, but don't overwrite any error condition
|
|
|
|
/* Stop autoservice on the peer channel, but don't overwrite any error condition
|
|
|
|
that has occurred previously while acting on the primary channel */
|
|
|
|
that has occurred previously while acting on the primary channel */
|
|
|
|
if (ast_autoservice_stop(peer) && !res)
|
|
|
|
if (ast_autoservice_stop(peer) && !res) {
|
|
|
|
res = -1;
|
|
|
|
res = -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (silgen) {
|
|
|
|
if (silgen) {
|
|
|
@ -371,11 +390,13 @@ static void linear_release(struct ast_channel *chan, void *params)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct linear_state *ls = params;
|
|
|
|
struct linear_state *ls = params;
|
|
|
|
|
|
|
|
|
|
|
|
if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt))
|
|
|
|
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);
|
|
|
|
ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (ls->autoclose)
|
|
|
|
if (ls->autoclose) {
|
|
|
|
close(ls->fd);
|
|
|
|
close(ls->fd);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ast_free(params);
|
|
|
|
ast_free(params);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -402,8 +423,9 @@ static int linear_generator(struct ast_channel *chan, void *data, int len, int s
|
|
|
|
f.datalen = res;
|
|
|
|
f.datalen = res;
|
|
|
|
f.samples = res / 2;
|
|
|
|
f.samples = res / 2;
|
|
|
|
ast_write(chan, &f);
|
|
|
|
ast_write(chan, &f);
|
|
|
|
if (res == len)
|
|
|
|
if (res == len) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -412,14 +434,16 @@ static void *linear_alloc(struct ast_channel *chan, void *params)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
struct linear_state *ls = params;
|
|
|
|
struct linear_state *ls = params;
|
|
|
|
|
|
|
|
|
|
|
|
if (!params)
|
|
|
|
if (!params) {
|
|
|
|
return NULL;
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* In this case, params is already malloc'd */
|
|
|
|
/* In this case, params is already malloc'd */
|
|
|
|
if (ls->allowoverride)
|
|
|
|
if (ls->allowoverride) {
|
|
|
|
ast_set_flag(chan, AST_FLAG_WRITE_INT);
|
|
|
|
ast_set_flag(chan, AST_FLAG_WRITE_INT);
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
ast_clear_flag(chan, AST_FLAG_WRITE_INT);
|
|
|
|
ast_clear_flag(chan, AST_FLAG_WRITE_INT);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ls->origwfmt = chan->writeformat;
|
|
|
|
ls->origwfmt = chan->writeformat;
|
|
|
|
|
|
|
|
|
|
|
@ -446,13 +470,15 @@ int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, in
|
|
|
|
int res = -1;
|
|
|
|
int res = -1;
|
|
|
|
int autoclose = 0;
|
|
|
|
int autoclose = 0;
|
|
|
|
if (fd < 0) {
|
|
|
|
if (fd < 0) {
|
|
|
|
if (ast_strlen_zero(filename))
|
|
|
|
if (ast_strlen_zero(filename)) {
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
autoclose = 1;
|
|
|
|
autoclose = 1;
|
|
|
|
if (filename[0] == '/')
|
|
|
|
if (filename[0] == '/') {
|
|
|
|
ast_copy_string(tmpf, filename, sizeof(tmpf));
|
|
|
|
ast_copy_string(tmpf, filename, sizeof(tmpf));
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", ast_config_AST_DATA_DIR, "sounds", filename);
|
|
|
|
snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", ast_config_AST_DATA_DIR, "sounds", filename);
|
|
|
|
|
|
|
|
}
|
|
|
|
if ((fd = open(tmpf, O_RDONLY)) < 0) {
|
|
|
|
if ((fd = open(tmpf, O_RDONLY)) < 0) {
|
|
|
|
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
|
|
|
|
ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
@ -479,28 +505,36 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
|
|
|
|
long pause_restart_point = 0;
|
|
|
|
long pause_restart_point = 0;
|
|
|
|
long offset = 0;
|
|
|
|
long offset = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (offsetms)
|
|
|
|
if (offsetms) {
|
|
|
|
offset = *offsetms * 8; /* XXX Assumes 8kHz */
|
|
|
|
offset = *offsetms * 8; /* XXX Assumes 8kHz */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (stop)
|
|
|
|
if (stop) {
|
|
|
|
blen += strlen(stop);
|
|
|
|
blen += strlen(stop);
|
|
|
|
if (suspend)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (suspend) {
|
|
|
|
blen += strlen(suspend);
|
|
|
|
blen += strlen(suspend);
|
|
|
|
if (restart)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
blen += strlen(restart);
|
|
|
|
blen += strlen(restart);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (blen > 2) {
|
|
|
|
if (blen > 2) {
|
|
|
|
breaks = alloca(blen + 1);
|
|
|
|
breaks = alloca(blen + 1);
|
|
|
|
breaks[0] = '\0';
|
|
|
|
breaks[0] = '\0';
|
|
|
|
if (stop)
|
|
|
|
if (stop) {
|
|
|
|
strcat(breaks, stop);
|
|
|
|
strcat(breaks, stop);
|
|
|
|
if (suspend)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (suspend) {
|
|
|
|
strcat(breaks, suspend);
|
|
|
|
strcat(breaks, suspend);
|
|
|
|
if (restart)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (restart) {
|
|
|
|
strcat(breaks, restart);
|
|
|
|
strcat(breaks, restart);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (chan->_state != AST_STATE_UP)
|
|
|
|
if (chan->_state != AST_STATE_UP) {
|
|
|
|
res = ast_answer(chan);
|
|
|
|
res = ast_answer(chan);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (file) {
|
|
|
|
if (file) {
|
|
|
|
if ((end = strchr(file, ':'))) {
|
|
|
|
if ((end = strchr(file, ':'))) {
|
|
|
@ -520,8 +554,9 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
|
|
|
|
pause_restart_point = 0;
|
|
|
|
pause_restart_point = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (end || offset < 0) {
|
|
|
|
else if (end || offset < 0) {
|
|
|
|
if (offset == -8)
|
|
|
|
if (offset == -8) {
|
|
|
|
offset = 0;
|
|
|
|
offset = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
ast_verb(3, "ControlPlayback seek to offset %ld from end\n", offset);
|
|
|
|
ast_verb(3, "ControlPlayback seek to offset %ld from end\n", offset);
|
|
|
|
|
|
|
|
|
|
|
|
ast_seekstream(chan->stream, offset, SEEK_END);
|
|
|
|
ast_seekstream(chan->stream, offset, SEEK_END);
|
|
|
@ -531,12 +566,13 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
|
|
|
|
ast_verb(3, "ControlPlayback seek to offset %ld\n", offset);
|
|
|
|
ast_verb(3, "ControlPlayback seek to offset %ld\n", offset);
|
|
|
|
ast_seekstream(chan->stream, offset, SEEK_SET);
|
|
|
|
ast_seekstream(chan->stream, offset, SEEK_SET);
|
|
|
|
offset = 0;
|
|
|
|
offset = 0;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
|
|
|
|
res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (res < 1)
|
|
|
|
if (res < 1) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* We go at next loop if we got the restart char */
|
|
|
|
/* We go at next loop if we got the restart char */
|
|
|
|
if (restart && strchr(restart, res)) {
|
|
|
|
if (restart && strchr(restart, res)) {
|
|
|
@ -549,11 +585,11 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
|
|
|
|
pause_restart_point = ast_tellstream(chan->stream);
|
|
|
|
pause_restart_point = ast_tellstream(chan->stream);
|
|
|
|
for (;;) {
|
|
|
|
for (;;) {
|
|
|
|
ast_stopstream(chan);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
res = ast_waitfordigit(chan, 1000);
|
|
|
|
if (!(res = ast_waitfordigit(chan, 1000))) {
|
|
|
|
if (!res)
|
|
|
|
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
|
else if (res == -1 || strchr(suspend, res) || (stop && strchr(stop, res)))
|
|
|
|
} else if (res == -1 || strchr(suspend, res) || (stop && strchr(stop, res))) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (res == *suspend) {
|
|
|
|
if (res == *suspend) {
|
|
|
|
res = 0;
|
|
|
|
res = 0;
|
|
|
@ -561,12 +597,14 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (res == -1)
|
|
|
|
if (res == -1) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* if we get one of our stop chars, return it to the calling function */
|
|
|
|
/* if we get one of our stop chars, return it to the calling function */
|
|
|
|
if (stop && strchr(stop, res))
|
|
|
|
if (stop && strchr(stop, res)) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (pause_restart_point) {
|
|
|
|
if (pause_restart_point) {
|
|
|
@ -579,12 +617,14 @@ int ast_control_streamfile(struct ast_channel *chan, const char *file,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (offsetms)
|
|
|
|
if (offsetms) {
|
|
|
|
*offsetms = offset / 8; /* samples --> ms ... XXX Assumes 8 kHz */
|
|
|
|
*offsetms = offset / 8; /* samples --> ms ... XXX Assumes 8 kHz */
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* If we are returning a digit cast it as char */
|
|
|
|
/* If we are returning a digit cast it as char */
|
|
|
|
if (res > 0 || chan->stream)
|
|
|
|
if (res > 0 || chan->stream) {
|
|
|
|
res = (char)res;
|
|
|
|
res = (char)res;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ast_stopstream(chan);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
|
|
|
|
|
|
|
@ -595,8 +635,9 @@ int ast_play_and_wait(struct ast_channel *chan, const char *fn)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int d = 0;
|
|
|
|
int d = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if ((d = ast_streamfile(chan, fn, chan->language)))
|
|
|
|
if ((d = ast_streamfile(chan, fn, chan->language))) {
|
|
|
|
return d;
|
|
|
|
return d;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
d = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
d = ast_waitstream(chan, AST_DIGIT_ANY);
|
|
|
|
|
|
|
|
|
|
|
@ -640,11 +681,13 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
struct ast_silence_generator *silgen = NULL;
|
|
|
|
struct ast_silence_generator *silgen = NULL;
|
|
|
|
char prependfile[80];
|
|
|
|
char prependfile[80];
|
|
|
|
|
|
|
|
|
|
|
|
if (silencethreshold < 0)
|
|
|
|
if (silencethreshold < 0) {
|
|
|
|
silencethreshold = global_silence_threshold;
|
|
|
|
silencethreshold = global_silence_threshold;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (maxsilence < 0)
|
|
|
|
if (maxsilence < 0) {
|
|
|
|
maxsilence = global_maxsilence;
|
|
|
|
maxsilence = global_maxsilence;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* barf if no pointer passed to store duration in */
|
|
|
|
/* barf if no pointer passed to store duration in */
|
|
|
|
if (!duration) {
|
|
|
|
if (!duration) {
|
|
|
@ -656,12 +699,15 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
|
|
|
|
snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
|
|
|
|
|
|
|
|
|
|
|
|
if (playfile || beep) {
|
|
|
|
if (playfile || beep) {
|
|
|
|
if (!beep)
|
|
|
|
if (!beep) {
|
|
|
|
d = ast_play_and_wait(chan, playfile);
|
|
|
|
d = ast_play_and_wait(chan, playfile);
|
|
|
|
if (d > -1)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d > -1) {
|
|
|
|
d = ast_stream_and_wait(chan, "beep", "");
|
|
|
|
d = ast_stream_and_wait(chan, "beep", "");
|
|
|
|
if (d < 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (d < 0) {
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (prepend) {
|
|
|
|
if (prepend) {
|
|
|
@ -689,12 +735,14 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
|
|
|
|
others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
|
|
|
|
ast_verb(3, "x=%d, open writing: %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
|
|
|
|
ast_verb(3, "x=%d, open writing: %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
|
|
|
|
|
|
|
|
|
|
|
|
if (!others[x])
|
|
|
|
if (!others[x]) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (path)
|
|
|
|
if (path) {
|
|
|
|
ast_unlock_path(path);
|
|
|
|
ast_unlock_path(path);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (maxsilence > 0) {
|
|
|
|
if (maxsilence > 0) {
|
|
|
|
sildet = ast_dsp_new(); /* Create the silence detector */
|
|
|
|
sildet = ast_dsp_new(); /* Create the silence detector */
|
|
|
@ -716,8 +764,9 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
/* Request a video update */
|
|
|
|
/* Request a video update */
|
|
|
|
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
|
|
|
|
ast_indicate(chan, AST_CONTROL_VIDUPDATE);
|
|
|
|
|
|
|
|
|
|
|
|
if (ast_opt_transmit_silence)
|
|
|
|
if (ast_opt_transmit_silence) {
|
|
|
|
silgen = ast_channel_start_silence_generator(chan);
|
|
|
|
silgen = ast_channel_start_silence_generator(chan);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (x == fmtcnt) {
|
|
|
|
if (x == fmtcnt) {
|
|
|
@ -725,12 +774,10 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
we read a digit or get a hangup */
|
|
|
|
we read a digit or get a hangup */
|
|
|
|
struct ast_frame *f;
|
|
|
|
struct ast_frame *f;
|
|
|
|
for (;;) {
|
|
|
|
for (;;) {
|
|
|
|
res = ast_waitfor(chan, 2000);
|
|
|
|
if (!(res = ast_waitfor(chan, 2000))) {
|
|
|
|
if (!res) {
|
|
|
|
|
|
|
|
ast_debug(1, "One waitfor failed, trying another\n");
|
|
|
|
ast_debug(1, "One waitfor failed, trying another\n");
|
|
|
|
/* Try one more time in case of masq */
|
|
|
|
/* Try one more time in case of masq */
|
|
|
|
res = ast_waitfor(chan, 2000);
|
|
|
|
if (!(res = ast_waitfor(chan, 2000))) {
|
|
|
|
if (!res) {
|
|
|
|
|
|
|
|
ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
|
|
|
|
ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
|
|
|
|
res = -1;
|
|
|
|
res = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -740,14 +787,15 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
f = NULL;
|
|
|
|
f = NULL;
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f = ast_read(chan);
|
|
|
|
if (!(f = ast_read(chan))) {
|
|
|
|
if (!f)
|
|
|
|
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (f->frametype == AST_FRAME_VOICE) {
|
|
|
|
if (f->frametype == AST_FRAME_VOICE) {
|
|
|
|
/* write each format */
|
|
|
|
/* write each format */
|
|
|
|
for (x = 0; x < fmtcnt; x++) {
|
|
|
|
for (x = 0; x < fmtcnt; x++) {
|
|
|
|
if (prepend && !others[x])
|
|
|
|
if (prepend && !others[x]) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
res = ast_writestream(others[x], f);
|
|
|
|
res = ast_writestream(others[x], f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -755,10 +803,11 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
if (maxsilence > 0) {
|
|
|
|
if (maxsilence > 0) {
|
|
|
|
int dspsilence = 0;
|
|
|
|
int dspsilence = 0;
|
|
|
|
ast_dsp_silence(sildet, f, &dspsilence);
|
|
|
|
ast_dsp_silence(sildet, f, &dspsilence);
|
|
|
|
if (dspsilence)
|
|
|
|
if (dspsilence) {
|
|
|
|
totalsilence = dspsilence;
|
|
|
|
totalsilence = dspsilence;
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
totalsilence = 0;
|
|
|
|
totalsilence = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (totalsilence > maxsilence) {
|
|
|
|
if (totalsilence > maxsilence) {
|
|
|
|
/* Ended happily with silence */
|
|
|
|
/* Ended happily with silence */
|
|
|
@ -820,8 +869,9 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!prepend) {
|
|
|
|
if (!prepend) {
|
|
|
|
if (silgen)
|
|
|
|
if (silgen) {
|
|
|
|
ast_channel_stop_silence_generator(chan, silgen);
|
|
|
|
ast_channel_stop_silence_generator(chan, silgen);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*!\note
|
|
|
|
/*!\note
|
|
|
@ -837,8 +887,9 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
|
|
|
|
|
|
|
|
if (!prepend) {
|
|
|
|
if (!prepend) {
|
|
|
|
for (x = 0; x < fmtcnt; x++) {
|
|
|
|
for (x = 0; x < fmtcnt; x++) {
|
|
|
|
if (!others[x])
|
|
|
|
if (!others[x]) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
/*!\note
|
|
|
|
/*!\note
|
|
|
|
* If we ended with silence, trim all but the first 200ms of silence
|
|
|
|
* 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
|
|
|
|
* off the recording. However, if we ended with '#', we don't want
|
|
|
@ -866,11 +917,13 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
for (x = 0; x < fmtcnt; x++) {
|
|
|
|
for (x = 0; x < fmtcnt; x++) {
|
|
|
|
snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[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);
|
|
|
|
realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
|
|
|
|
if (!others[x] || !realfiles[x])
|
|
|
|
if (!others[x] || !realfiles[x]) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
/*!\note Same logic as above. */
|
|
|
|
/*!\note Same logic as above. */
|
|
|
|
if (totalsilence)
|
|
|
|
if (totalsilence) {
|
|
|
|
ast_stream_rewind(others[x], totalsilence - 200);
|
|
|
|
ast_stream_rewind(others[x], totalsilence - 200);
|
|
|
|
|
|
|
|
}
|
|
|
|
ast_truncstream(others[x]);
|
|
|
|
ast_truncstream(others[x]);
|
|
|
|
/* add the original file too */
|
|
|
|
/* add the original file too */
|
|
|
|
while ((fr = ast_readframe(realfiles[x]))) {
|
|
|
|
while ((fr = ast_readframe(realfiles[x]))) {
|
|
|
@ -890,8 +943,9 @@ static int __ast_play_and_record(struct ast_channel *chan, const char *playfile,
|
|
|
|
if (outmsg == 2) {
|
|
|
|
if (outmsg == 2) {
|
|
|
|
ast_stream_and_wait(chan, "auth-thankyou", "");
|
|
|
|
ast_stream_and_wait(chan, "auth-thankyou", "");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (sildet)
|
|
|
|
if (sildet) {
|
|
|
|
ast_dsp_free(sildet);
|
|
|
|
ast_dsp_free(sildet);
|
|
|
|
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -924,20 +978,20 @@ int ast_app_group_split_group(const char *data, char *group, int group_max, char
|
|
|
|
if (!ast_strlen_zero(data)) {
|
|
|
|
if (!ast_strlen_zero(data)) {
|
|
|
|
ast_copy_string(tmp, data, sizeof(tmp));
|
|
|
|
ast_copy_string(tmp, data, sizeof(tmp));
|
|
|
|
grp = tmp;
|
|
|
|
grp = tmp;
|
|
|
|
cat = strchr(tmp, '@');
|
|
|
|
if ((cat = strchr(tmp, '@'))) {
|
|
|
|
if (cat) {
|
|
|
|
*cat++ = '\0';
|
|
|
|
*cat = '\0';
|
|
|
|
|
|
|
|
cat++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(grp))
|
|
|
|
if (!ast_strlen_zero(grp)) {
|
|
|
|
ast_copy_string(group, grp, group_max);
|
|
|
|
ast_copy_string(group, grp, group_max);
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
*group = '\0';
|
|
|
|
*group = '\0';
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(cat))
|
|
|
|
if (!ast_strlen_zero(cat)) {
|
|
|
|
ast_copy_string(category, cat, category_max);
|
|
|
|
ast_copy_string(category, cat, category_max);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -949,13 +1003,15 @@ int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
|
|
|
|
struct ast_group_info *gi = NULL;
|
|
|
|
struct ast_group_info *gi = NULL;
|
|
|
|
size_t len = 0;
|
|
|
|
size_t len = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category)))
|
|
|
|
if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* Calculate memory we will need if this is new */
|
|
|
|
/* Calculate memory we will need if this is new */
|
|
|
|
len = sizeof(*gi) + strlen(group) + 1;
|
|
|
|
len = sizeof(*gi) + strlen(group) + 1;
|
|
|
|
if (!ast_strlen_zero(category))
|
|
|
|
if (!ast_strlen_zero(category)) {
|
|
|
|
len += strlen(category) + 1;
|
|
|
|
len += strlen(category) + 1;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AST_RWLIST_WRLOCK(&groups);
|
|
|
|
AST_RWLIST_WRLOCK(&groups);
|
|
|
|
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) {
|
|
|
|
AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, list) {
|
|
|
@ -992,13 +1048,15 @@ int ast_app_group_get_count(const char *group, const char *category)
|
|
|
|
struct ast_group_info *gi = NULL;
|
|
|
|
struct ast_group_info *gi = NULL;
|
|
|
|
int count = 0;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (ast_strlen_zero(group))
|
|
|
|
if (ast_strlen_zero(group)) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AST_RWLIST_RDLOCK(&groups);
|
|
|
|
AST_RWLIST_RDLOCK(&groups);
|
|
|
|
AST_RWLIST_TRAVERSE(&groups, gi, list) {
|
|
|
|
AST_RWLIST_TRAVERSE(&groups, gi, list) {
|
|
|
|
if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category))))
|
|
|
|
if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
|
|
|
|
count++;
|
|
|
|
count++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_RWLIST_UNLOCK(&groups);
|
|
|
|
AST_RWLIST_UNLOCK(&groups);
|
|
|
|
|
|
|
|
|
|
|
@ -1011,17 +1069,20 @@ int ast_app_group_match_get_count(const char *groupmatch, const char *category)
|
|
|
|
regex_t regexbuf;
|
|
|
|
regex_t regexbuf;
|
|
|
|
int count = 0;
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (ast_strlen_zero(groupmatch))
|
|
|
|
if (ast_strlen_zero(groupmatch)) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* if regex compilation fails, return zero matches */
|
|
|
|
/* if regex compilation fails, return zero matches */
|
|
|
|
if (regcomp(®exbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
|
|
|
|
if (regcomp(®exbuf, groupmatch, REG_EXTENDED | REG_NOSUB)) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
AST_RWLIST_RDLOCK(&groups);
|
|
|
|
AST_RWLIST_RDLOCK(&groups);
|
|
|
|
AST_RWLIST_TRAVERSE(&groups, gi, list) {
|
|
|
|
AST_RWLIST_TRAVERSE(&groups, gi, list) {
|
|
|
|
if (!regexec(®exbuf, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category))))
|
|
|
|
if (!regexec(®exbuf, gi->group, 0, NULL, 0) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
|
|
|
|
count++;
|
|
|
|
count++;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
AST_RWLIST_UNLOCK(&groups);
|
|
|
|
AST_RWLIST_UNLOCK(&groups);
|
|
|
|
|
|
|
|
|
|
|
@ -1092,8 +1153,9 @@ unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arra
|
|
|
|
char *scan, *wasdelim = NULL;
|
|
|
|
char *scan, *wasdelim = NULL;
|
|
|
|
int paren = 0, quote = 0;
|
|
|
|
int paren = 0, quote = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (!buf || !array || !arraylen)
|
|
|
|
if (!buf || !array || !arraylen) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
memset(array, 0, arraylen * sizeof(*array));
|
|
|
|
memset(array, 0, arraylen * sizeof(*array));
|
|
|
|
|
|
|
|
|
|
|
@ -1102,11 +1164,12 @@ unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arra
|
|
|
|
for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
|
|
|
|
for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
|
|
|
|
array[argc] = scan;
|
|
|
|
array[argc] = scan;
|
|
|
|
for (; *scan; scan++) {
|
|
|
|
for (; *scan; scan++) {
|
|
|
|
if (*scan == '(')
|
|
|
|
if (*scan == '(') {
|
|
|
|
paren++;
|
|
|
|
paren++;
|
|
|
|
else if (*scan == ')') {
|
|
|
|
} else if (*scan == ')') {
|
|
|
|
if (paren)
|
|
|
|
if (paren) {
|
|
|
|
paren--;
|
|
|
|
paren--;
|
|
|
|
|
|
|
|
}
|
|
|
|
} else if (*scan == '"' && delim != '"') {
|
|
|
|
} else if (*scan == '"' && delim != '"') {
|
|
|
|
quote = quote ? 0 : 1;
|
|
|
|
quote = quote ? 0 : 1;
|
|
|
|
/* Remove quote character from argument */
|
|
|
|
/* Remove quote character from argument */
|
|
|
@ -1154,8 +1217,9 @@ static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path)
|
|
|
|
|
|
|
|
|
|
|
|
snprintf(s, strlen(path) + 9, "%s/.lock", path);
|
|
|
|
snprintf(s, strlen(path) + 9, "%s/.lock", path);
|
|
|
|
start = time(NULL);
|
|
|
|
start = time(NULL);
|
|
|
|
while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
|
|
|
|
while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) {
|
|
|
|
usleep(1);
|
|
|
|
sched_yield();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
unlink(fs);
|
|
|
|
unlink(fs);
|
|
|
|
|
|
|
|
|
|
|
@ -1177,9 +1241,9 @@ static int ast_unlock_path_lockfile(const char *path)
|
|
|
|
|
|
|
|
|
|
|
|
snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
|
|
|
|
snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
|
|
|
|
|
|
|
|
|
|
|
|
if ((res = unlink(s)))
|
|
|
|
if ((res = unlink(s))) {
|
|
|
|
ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
|
|
|
|
ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
|
|
|
|
else {
|
|
|
|
} else {
|
|
|
|
ast_debug(1, "Unlocked path '%s'\n", path);
|
|
|
|
ast_debug(1, "Unlocked path '%s'\n", path);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1196,10 +1260,12 @@ static AST_LIST_HEAD_STATIC(path_lock_list, path_lock);
|
|
|
|
|
|
|
|
|
|
|
|
static void path_lock_destroy(struct path_lock *obj)
|
|
|
|
static void path_lock_destroy(struct path_lock *obj)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
if (obj->fd >= 0)
|
|
|
|
if (obj->fd >= 0) {
|
|
|
|
close(obj->fd);
|
|
|
|
close(obj->fd);
|
|
|
|
if (obj->path)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (obj->path) {
|
|
|
|
free(obj->path);
|
|
|
|
free(obj->path);
|
|
|
|
|
|
|
|
}
|
|
|
|
free(obj);
|
|
|
|
free(obj);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1229,14 +1295,12 @@ static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
|
|
|
|
return AST_LOCK_FAILURE;
|
|
|
|
return AST_LOCK_FAILURE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fd = open(fs, O_WRONLY | O_CREAT, 0600);
|
|
|
|
if ((fd = open(fs, O_WRONLY | O_CREAT, 0600)) < 0) {
|
|
|
|
if (fd < 0) {
|
|
|
|
|
|
|
|
ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
|
|
|
|
ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
|
|
|
|
fs, strerror(errno));
|
|
|
|
fs, strerror(errno));
|
|
|
|
return AST_LOCK_PATH_NOT_FOUND;
|
|
|
|
return AST_LOCK_PATH_NOT_FOUND;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pl = ast_calloc(1, sizeof(*pl));
|
|
|
|
if (!(pl = ast_calloc(1, sizeof(*pl)))) {
|
|
|
|
if (!pl) {
|
|
|
|
|
|
|
|
/* We don't unlink the lock file here, on the possibility that
|
|
|
|
/* We don't unlink the lock file here, on the possibility that
|
|
|
|
* someone else created it - better to leave a little mess
|
|
|
|
* someone else created it - better to leave a little mess
|
|
|
|
* than create a big one by destroying someone else's lock
|
|
|
|
* than create a big one by destroying someone else's lock
|
|
|
@ -1249,11 +1313,11 @@ static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
|
|
|
|
pl->path = strdup(path);
|
|
|
|
pl->path = strdup(path);
|
|
|
|
|
|
|
|
|
|
|
|
time(&start);
|
|
|
|
time(&start);
|
|
|
|
while ((
|
|
|
|
while (
|
|
|
|
#ifdef SOLARIS
|
|
|
|
#ifdef SOLARIS
|
|
|
|
(res = fcntl(pl->fd, F_SETLK, fcntl(pl->fd, F_GETFL) | O_NONBLOCK)) < 0) &&
|
|
|
|
((res = fcntl(pl->fd, F_SETLK, fcntl(pl->fd, F_GETFL) | O_NONBLOCK)) < 0) &&
|
|
|
|
#else
|
|
|
|
#else
|
|
|
|
(res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
|
|
|
|
((res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
(errno == EWOULDBLOCK) &&
|
|
|
|
(errno == EWOULDBLOCK) &&
|
|
|
|
(time(NULL) - start < 5))
|
|
|
|
(time(NULL) - start < 5))
|
|
|
@ -1312,9 +1376,10 @@ static int ast_unlock_path_flock(const char *path)
|
|
|
|
unlink(s);
|
|
|
|
unlink(s);
|
|
|
|
path_lock_destroy(p);
|
|
|
|
path_lock_destroy(p);
|
|
|
|
ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
|
|
|
|
ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
|
|
|
|
} else
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_DEBUG, "Failed to unlock path '%s': "
|
|
|
|
ast_log(LOG_DEBUG, "Failed to unlock path '%s': "
|
|
|
|
"lock not found\n", path);
|
|
|
|
"lock not found\n", path);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1398,22 +1463,17 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char
|
|
|
|
case '3':
|
|
|
|
case '3':
|
|
|
|
message_exists = 0;
|
|
|
|
message_exists = 0;
|
|
|
|
/* Record */
|
|
|
|
/* Record */
|
|
|
|
if (recorded == 1)
|
|
|
|
ast_verb(3, "R%secording\n", recorded == 1 ? "e-r" : "");
|
|
|
|
ast_verb(3, "Re-recording\n");
|
|
|
|
|
|
|
|
else
|
|
|
|
|
|
|
|
ast_verb(3, "Recording\n");
|
|
|
|
|
|
|
|
recorded = 1;
|
|
|
|
recorded = 1;
|
|
|
|
cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path);
|
|
|
|
if ((cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path)) == -1) {
|
|
|
|
if (cmd == -1) {
|
|
|
|
/* User has hung up, no options to give */
|
|
|
|
/* User has hung up, no options to give */
|
|
|
|
|
|
|
|
return cmd;
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cmd == '0') {
|
|
|
|
if (cmd == '0') {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
} else if (cmd == '*') {
|
|
|
|
} else if (cmd == '*') {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
else {
|
|
|
|
|
|
|
|
/* If all is well, a message exists */
|
|
|
|
/* If all is well, a message exists */
|
|
|
|
message_exists = 1;
|
|
|
|
message_exists = 1;
|
|
|
|
cmd = 0;
|
|
|
|
cmd = 0;
|
|
|
@ -1432,15 +1492,15 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
if (message_exists) {
|
|
|
|
if (message_exists) {
|
|
|
|
cmd = ast_play_and_wait(chan, "vm-review");
|
|
|
|
cmd = ast_play_and_wait(chan, "vm-review");
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
else {
|
|
|
|
if (!(cmd = ast_play_and_wait(chan, "vm-torerecord"))) {
|
|
|
|
cmd = ast_play_and_wait(chan, "vm-torerecord");
|
|
|
|
|
|
|
|
if (!cmd)
|
|
|
|
|
|
|
|
cmd = ast_waitfordigit(chan, 600);
|
|
|
|
cmd = ast_waitfordigit(chan, 600);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!cmd)
|
|
|
|
if (!cmd) {
|
|
|
|
cmd = ast_waitfordigit(chan, 6000);
|
|
|
|
cmd = ast_waitfordigit(chan, 6000);
|
|
|
|
|
|
|
|
}
|
|
|
|
if (!cmd) {
|
|
|
|
if (!cmd) {
|
|
|
|
attempts++;
|
|
|
|
attempts++;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1449,8 +1509,9 @@ int ast_record_review(struct ast_channel *chan, const char *playfile, const char
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cmd == 't')
|
|
|
|
if (cmd == 't') {
|
|
|
|
cmd = 0;
|
|
|
|
cmd = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
return cmd;
|
|
|
|
return cmd;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1494,15 +1555,15 @@ static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
case AST_ACTION_MENU:
|
|
|
|
case AST_ACTION_MENU:
|
|
|
|
res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata);
|
|
|
|
if ((res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata)) == -2) {
|
|
|
|
/* Do not pass entry errors back up, treat as though it was an "UPONE" */
|
|
|
|
/* Do not pass entry errors back up, treat as though it was an "UPONE" */
|
|
|
|
if (res == -2)
|
|
|
|
|
|
|
|
res = 0;
|
|
|
|
res = 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
case AST_ACTION_WAITOPTION:
|
|
|
|
case AST_ACTION_WAITOPTION:
|
|
|
|
res = ast_waitfordigit(chan, chan->pbx ? chan->pbx->rtimeoutms : 10000);
|
|
|
|
if (!(res = ast_waitfordigit(chan, chan->pbx ? chan->pbx->rtimeoutms : 10000))) {
|
|
|
|
if (!res)
|
|
|
|
|
|
|
|
return 't';
|
|
|
|
return 't';
|
|
|
|
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
case AST_ACTION_CALLBACK:
|
|
|
|
case AST_ACTION_CALLBACK:
|
|
|
|
ivr_func = option->adata;
|
|
|
|
ivr_func = option->adata;
|
|
|
@ -1517,34 +1578,39 @@ static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option,
|
|
|
|
c = ast_strdupa(option->adata);
|
|
|
|
c = ast_strdupa(option->adata);
|
|
|
|
while ((n = strsep(&c, ";"))) {
|
|
|
|
while ((n = strsep(&c, ";"))) {
|
|
|
|
if ((res = ast_stream_and_wait(chan, n,
|
|
|
|
if ((res = ast_stream_and_wait(chan, n,
|
|
|
|
(option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
|
|
|
|
(option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : ""))) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_stopstream(chan);
|
|
|
|
ast_stopstream(chan);
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|
ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
|
|
|
|
ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int option_exists(struct ast_ivr_menu *menu, char *option)
|
|
|
|
static int option_exists(struct ast_ivr_menu *menu, char *option)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int x;
|
|
|
|
for (x = 0; menu->options[x].option; x++)
|
|
|
|
for (x = 0; menu->options[x].option; x++) {
|
|
|
|
if (!strcasecmp(menu->options[x].option, option))
|
|
|
|
if (!strcasecmp(menu->options[x].option, option)) {
|
|
|
|
return x;
|
|
|
|
return x;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int option_matchmore(struct ast_ivr_menu *menu, char *option)
|
|
|
|
static int option_matchmore(struct ast_ivr_menu *menu, char *option)
|
|
|
|
{
|
|
|
|
{
|
|
|
|
int x;
|
|
|
|
int x;
|
|
|
|
for (x = 0; menu->options[x].option; x++)
|
|
|
|
for (x = 0; menu->options[x].option; x++) {
|
|
|
|
if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
|
|
|
|
if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
|
|
|
|
(menu->options[x].option[strlen(option)]))
|
|
|
|
(menu->options[x].option[strlen(option)])) {
|
|
|
|
return x;
|
|
|
|
return x;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -1554,11 +1620,12 @@ static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, c
|
|
|
|
int ms;
|
|
|
|
int ms;
|
|
|
|
while (option_matchmore(menu, exten)) {
|
|
|
|
while (option_matchmore(menu, exten)) {
|
|
|
|
ms = chan->pbx ? chan->pbx->dtimeoutms : 5000;
|
|
|
|
ms = chan->pbx ? chan->pbx->dtimeoutms : 5000;
|
|
|
|
if (strlen(exten) >= maxexten - 1)
|
|
|
|
if (strlen(exten) >= maxexten - 1) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
res = ast_waitfordigit(chan, ms);
|
|
|
|
}
|
|
|
|
if (res < 1)
|
|
|
|
if ((res = ast_waitfordigit(chan, ms)) < 1) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
exten[strlen(exten) + 1] = '\0';
|
|
|
|
exten[strlen(exten) + 1] = '\0';
|
|
|
|
exten[strlen(exten)] = res;
|
|
|
|
exten[strlen(exten)] = res;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1584,28 +1651,31 @@ static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_me
|
|
|
|
if (!strcasecmp(menu->options[pos].option, exten)) {
|
|
|
|
if (!strcasecmp(menu->options[pos].option, exten)) {
|
|
|
|
res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
|
|
|
|
res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
|
|
|
|
ast_debug(1, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
|
|
|
|
ast_debug(1, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
|
|
|
|
if (res < 0)
|
|
|
|
if (res < 0) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
else if (res & RES_UPONE)
|
|
|
|
} else if (res & RES_UPONE) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
else if (res & RES_EXIT)
|
|
|
|
} else if (res & RES_EXIT) {
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
else if (res & RES_REPEAT) {
|
|
|
|
} else if (res & RES_REPEAT) {
|
|
|
|
int maxretries = res & 0xffff;
|
|
|
|
int maxretries = res & 0xffff;
|
|
|
|
if ((res & RES_RESTART) == RES_RESTART) {
|
|
|
|
if ((res & RES_RESTART) == RES_RESTART) {
|
|
|
|
retries = 0;
|
|
|
|
retries = 0;
|
|
|
|
} else
|
|
|
|
} else {
|
|
|
|
retries++;
|
|
|
|
retries++;
|
|
|
|
if (!maxretries)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!maxretries) {
|
|
|
|
maxretries = 3;
|
|
|
|
maxretries = 3;
|
|
|
|
|
|
|
|
}
|
|
|
|
if ((maxretries > 0) && (retries >= maxretries)) {
|
|
|
|
if ((maxretries > 0) && (retries >= maxretries)) {
|
|
|
|
ast_debug(1, "Max retries %d exceeded\n", maxretries);
|
|
|
|
ast_debug(1, "Max retries %d exceeded\n", maxretries);
|
|
|
|
return -2;
|
|
|
|
return -2;
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
if (option_exists(menu, "g") > -1)
|
|
|
|
if (option_exists(menu, "g") > -1) {
|
|
|
|
strcpy(exten, "g");
|
|
|
|
strcpy(exten, "g");
|
|
|
|
else if (option_exists(menu, "s") > -1)
|
|
|
|
} else if (option_exists(menu, "s") > -1) {
|
|
|
|
strcpy(exten, "s");
|
|
|
|
strcpy(exten, "s");
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pos = 0;
|
|
|
|
pos = 0;
|
|
|
|
continue;
|
|
|
|
continue;
|
|
|
@ -1613,8 +1683,9 @@ static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_me
|
|
|
|
ast_debug(1, "Got start of extension, %c\n", res);
|
|
|
|
ast_debug(1, "Got start of extension, %c\n", res);
|
|
|
|
exten[1] = '\0';
|
|
|
|
exten[1] = '\0';
|
|
|
|
exten[0] = res;
|
|
|
|
exten[0] = res;
|
|
|
|
if ((res = read_newoption(chan, menu, exten, sizeof(exten))))
|
|
|
|
if ((res = read_newoption(chan, menu, exten, sizeof(exten)))) {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
if (option_exists(menu, exten) < 0) {
|
|
|
|
if (option_exists(menu, exten) < 0) {
|
|
|
|
if (option_exists(menu, "i")) {
|
|
|
|
if (option_exists(menu, "i")) {
|
|
|
|
ast_debug(1, "Invalid extension entered, going to 'i'!\n");
|
|
|
|
ast_debug(1, "Invalid extension entered, going to 'i'!\n");
|
|
|
@ -1637,10 +1708,11 @@ static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_me
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast_debug(1, "Stopping option '%s', res is %d\n", exten, res);
|
|
|
|
ast_debug(1, "Stopping option '%s', res is %d\n", exten, res);
|
|
|
|
pos = 0;
|
|
|
|
pos = 0;
|
|
|
|
if (!strcasecmp(exten, "s"))
|
|
|
|
if (!strcasecmp(exten, "s")) {
|
|
|
|
strcpy(exten, "g");
|
|
|
|
strcpy(exten, "g");
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return res;
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -1694,8 +1766,9 @@ int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags
|
|
|
|
|
|
|
|
|
|
|
|
ast_clear_flag(flags, AST_FLAGS_ALL);
|
|
|
|
ast_clear_flag(flags, AST_FLAGS_ALL);
|
|
|
|
|
|
|
|
|
|
|
|
if (!optstr)
|
|
|
|
if (!optstr) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s = optstr;
|
|
|
|
s = optstr;
|
|
|
|
while (*s) {
|
|
|
|
while (*s) {
|
|
|
@ -1705,8 +1778,9 @@ int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags
|
|
|
|
/* Has argument */
|
|
|
|
/* Has argument */
|
|
|
|
arg = ++s;
|
|
|
|
arg = ++s;
|
|
|
|
if ((s = strchr(s, ')'))) {
|
|
|
|
if ((s = strchr(s, ')'))) {
|
|
|
|
if (argloc)
|
|
|
|
if (argloc) {
|
|
|
|
args[argloc - 1] = arg;
|
|
|
|
args[argloc - 1] = arg;
|
|
|
|
|
|
|
|
}
|
|
|
|
*s++ = '\0';
|
|
|
|
*s++ = '\0';
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
|
|
|
|
ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
|
|
|
@ -1734,8 +1808,9 @@ int ast_app_parse_options64(const struct ast_app_option *options, struct ast_fla
|
|
|
|
|
|
|
|
|
|
|
|
flags->flags = 0;
|
|
|
|
flags->flags = 0;
|
|
|
|
|
|
|
|
|
|
|
|
if (!optstr)
|
|
|
|
if (!optstr) {
|
|
|
|
return 0;
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
s = optstr;
|
|
|
|
s = optstr;
|
|
|
|
while (*s) {
|
|
|
|
while (*s) {
|
|
|
@ -1746,8 +1821,9 @@ int ast_app_parse_options64(const struct ast_app_option *options, struct ast_fla
|
|
|
|
/* Has argument */
|
|
|
|
/* Has argument */
|
|
|
|
arg = ++s;
|
|
|
|
arg = ++s;
|
|
|
|
if ((s = strchr(s, ')'))) {
|
|
|
|
if ((s = strchr(s, ')'))) {
|
|
|
|
if (argloc)
|
|
|
|
if (argloc) {
|
|
|
|
args[argloc - 1] = arg;
|
|
|
|
args[argloc - 1] = arg;
|
|
|
|
|
|
|
|
}
|
|
|
|
*s++ = '\0';
|
|
|
|
*s++ = '\0';
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
|
|
|
|
ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
|
|
|
@ -1799,12 +1875,13 @@ int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
|
|
|
|
/* Hexadecimal */
|
|
|
|
/* Hexadecimal */
|
|
|
|
if (strchr("0123456789ABCDEFabcdef", *(stream + 2)) && *(stream + 2) != '\0') {
|
|
|
|
if (strchr("0123456789ABCDEFabcdef", *(stream + 2)) && *(stream + 2) != '\0') {
|
|
|
|
*consumed = 3;
|
|
|
|
*consumed = 3;
|
|
|
|
if (*(stream + 2) <= '9')
|
|
|
|
if (*(stream + 2) <= '9') {
|
|
|
|
*result = *(stream + 2) - '0';
|
|
|
|
*result = *(stream + 2) - '0';
|
|
|
|
else if (*(stream + 2) <= 'F')
|
|
|
|
} else if (*(stream + 2) <= 'F') {
|
|
|
|
*result = *(stream + 2) - 'A' + 10;
|
|
|
|
*result = *(stream + 2) - 'A' + 10;
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
*result = *(stream + 2) - 'a' + 10;
|
|
|
|
*result = *(stream + 2) - 'a' + 10;
|
|
|
|
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
ast_log(LOG_ERROR, "Illegal character '%c' in hexadecimal string\n", *(stream + 2));
|
|
|
|
ast_log(LOG_ERROR, "Illegal character '%c' in hexadecimal string\n", *(stream + 2));
|
|
|
|
return -1;
|
|
|
|
return -1;
|
|
|
@ -1813,12 +1890,13 @@ int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
|
|
|
|
if (strchr("0123456789ABCDEFabcdef", *(stream + 3)) && *(stream + 3) != '\0') {
|
|
|
|
if (strchr("0123456789ABCDEFabcdef", *(stream + 3)) && *(stream + 3) != '\0') {
|
|
|
|
*consumed = 4;
|
|
|
|
*consumed = 4;
|
|
|
|
*result <<= 4;
|
|
|
|
*result <<= 4;
|
|
|
|
if (*(stream + 3) <= '9')
|
|
|
|
if (*(stream + 3) <= '9') {
|
|
|
|
*result += *(stream + 3) - '0';
|
|
|
|
*result += *(stream + 3) - '0';
|
|
|
|
else if (*(stream + 3) <= 'F')
|
|
|
|
} else if (*(stream + 3) <= 'F') {
|
|
|
|
*result += *(stream + 3) - 'A' + 10;
|
|
|
|
*result += *(stream + 3) - 'A' + 10;
|
|
|
|
else
|
|
|
|
} else {
|
|
|
|
*result += *(stream + 3) - 'a' + 10;
|
|
|
|
*result += *(stream + 3) - 'a' + 10;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
case '0':
|
|
|
|
case '0':
|
|
|
@ -1831,8 +1909,9 @@ int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
|
|
|
|
*result <<= 3;
|
|
|
|
*result <<= 3;
|
|
|
|
*result += *(stream + i) - '0';
|
|
|
|
*result += *(stream + i) - '0';
|
|
|
|
ast_debug(5, "is now %d\n", *result);
|
|
|
|
ast_debug(5, "is now %d\n", *result);
|
|
|
|
} else
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
default:
|
|
|
|