00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <stdio.h>
00026 #include <stdlib.h>
00027 #include <string.h>
00028 #include <sys/time.h>
00029 #include <signal.h>
00030 #include <errno.h>
00031 #include <unistd.h>
00032 #include <dirent.h>
00033 #include <sys/types.h>
00034 #include <sys/stat.h>
00035 #include <regex.h>
00036
00037 #include "asterisk.h"
00038
00039 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 37441 $")
00040
00041 #include "asterisk/channel.h"
00042 #include "asterisk/pbx.h"
00043 #include "asterisk/file.h"
00044 #include "asterisk/app.h"
00045 #include "asterisk/dsp.h"
00046 #include "asterisk/logger.h"
00047 #include "asterisk/options.h"
00048 #include "asterisk/utils.h"
00049 #include "asterisk/lock.h"
00050 #include "asterisk/indications.h"
00051
00052 #define MAX_OTHER_FORMATS 10
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062 int ast_app_dtget(struct ast_channel *chan, const char *context, char *collect, size_t size, int maxlen, int timeout)
00063 {
00064 struct tone_zone_sound *ts;
00065 int res=0, x=0;
00066
00067 if(maxlen > size)
00068 maxlen = size;
00069
00070 if(!timeout && chan->pbx)
00071 timeout = chan->pbx->dtimeout;
00072 else if(!timeout)
00073 timeout = 5;
00074
00075 ts = ast_get_indication_tone(chan->zone,"dial");
00076 if (ts && ts->data[0])
00077 res = ast_playtones_start(chan, 0, ts->data, 0);
00078 else
00079 ast_log(LOG_NOTICE,"Huh....? no dial for indications?\n");
00080
00081 for (x = strlen(collect); strlen(collect) < maxlen; ) {
00082 res = ast_waitfordigit(chan, timeout);
00083 if (!ast_ignore_pattern(context, collect))
00084 ast_playtones_stop(chan);
00085 if (res < 1)
00086 break;
00087 collect[x++] = res;
00088 if (!ast_matchmore_extension(chan, context, collect, 1, chan->cid.cid_num)) {
00089 if (collect[x-1] == '#') {
00090
00091 collect[x-1] = '\0';
00092 }
00093 break;
00094 }
00095 }
00096 if (res >= 0) {
00097 if (ast_exists_extension(chan, context, collect, 1, chan->cid.cid_num))
00098 res = 1;
00099 else
00100 res = 0;
00101 }
00102 return res;
00103 }
00104
00105
00106
00107
00108
00109 int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
00110 {
00111 int res,to,fto;
00112
00113 if (maxlen)
00114 s[0] = '\0';
00115 if (prompt) {
00116 res = ast_streamfile(c, prompt, c->language);
00117 if (res < 0)
00118 return res;
00119 }
00120 fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
00121 to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
00122
00123 if (timeout > 0)
00124 fto = to = timeout;
00125 if (timeout < 0)
00126 fto = to = 1000000000;
00127 res = ast_readstring(c, s, maxlen, to, fto, "#");
00128 return res;
00129 }
00130
00131
00132 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
00133 {
00134 int res,to,fto;
00135 if (prompt) {
00136 res = ast_streamfile(c, prompt, c->language);
00137 if (res < 0)
00138 return res;
00139 }
00140 fto = 6000;
00141 to = 2000;
00142 if (timeout > 0)
00143 fto = to = timeout;
00144 if (timeout < 0)
00145 fto = to = 1000000000;
00146 res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
00147 return res;
00148 }
00149
00150 int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
00151 {
00152 int res;
00153 struct ast_filestream *writer;
00154 int rfmt;
00155 int totalms=0, total;
00156
00157 struct ast_frame *f;
00158 struct ast_dsp *sildet;
00159
00160 if (prompt) {
00161 res = ast_streamfile(c, prompt, c->language);
00162 if (res < 0)
00163 return res;
00164 res = ast_waitstream(c,"");
00165 if (res < 0)
00166 return res;
00167 }
00168 rfmt = c->readformat;
00169 res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
00170 if (res < 0) {
00171 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00172 return -1;
00173 }
00174 sildet = ast_dsp_new();
00175 if (!sildet) {
00176 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00177 return -1;
00178 }
00179 writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
00180 if (!writer) {
00181 ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
00182 ast_dsp_free(sildet);
00183 return -1;
00184 }
00185 for(;;) {
00186 if ((res = ast_waitfor(c, 2000)) < 0) {
00187 ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
00188 break;
00189 }
00190 if (res) {
00191 f = ast_read(c);
00192 if (!f) {
00193 ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
00194 break;
00195 }
00196 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
00197
00198 ast_frfree(f);
00199 break;
00200 } else if (f->frametype == AST_FRAME_VOICE) {
00201 ast_dsp_silence(sildet, f, &total);
00202 if (total > silence) {
00203
00204 ast_frfree(f);
00205 break;
00206 }
00207 totalms += f->samples / 8;
00208 if (totalms > maxsec * 1000) {
00209
00210 ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
00211 ast_frfree(f);
00212 break;
00213 }
00214 res = ast_writestream(writer, f);
00215 if (res < 0) {
00216 ast_log(LOG_WARNING, "Failed to write to stream at %s!\n", dest);
00217 ast_frfree(f);
00218 break;
00219 }
00220
00221 }
00222 ast_frfree(f);
00223 }
00224 }
00225 res = ast_set_read_format(c, rfmt);
00226 if (res)
00227 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
00228 ast_dsp_free(sildet);
00229 ast_closestream(writer);
00230 return 0;
00231 }
00232
00233 static int (*ast_has_voicemail_func)(const char *mailbox, const char *folder) = NULL;
00234 static int (*ast_messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs) = NULL;
00235
00236 void ast_install_vm_functions(int (*has_voicemail_func)(const char *mailbox, const char *folder),
00237 int (*messagecount_func)(const char *mailbox, int *newmsgs, int *oldmsgs))
00238 {
00239 ast_has_voicemail_func = has_voicemail_func;
00240 ast_messagecount_func = messagecount_func;
00241 }
00242
00243 void ast_uninstall_vm_functions(void)
00244 {
00245 ast_has_voicemail_func = NULL;
00246 ast_messagecount_func = NULL;
00247 }
00248
00249 int ast_app_has_voicemail(const char *mailbox, const char *folder)
00250 {
00251 static int warned = 0;
00252 if (ast_has_voicemail_func)
00253 return ast_has_voicemail_func(mailbox, folder);
00254
00255 if ((option_verbose > 2) && !warned) {
00256 ast_verbose(VERBOSE_PREFIX_3 "Message check requested for mailbox %s/folder %s but voicemail not loaded.\n", mailbox, folder ? folder : "INBOX");
00257 warned++;
00258 }
00259 return 0;
00260 }
00261
00262
00263 int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
00264 {
00265 static int warned = 0;
00266 if (newmsgs)
00267 *newmsgs = 0;
00268 if (oldmsgs)
00269 *oldmsgs = 0;
00270 if (ast_messagecount_func)
00271 return ast_messagecount_func(mailbox, newmsgs, oldmsgs);
00272
00273 if (!warned && (option_verbose > 2)) {
00274 warned++;
00275 ast_verbose(VERBOSE_PREFIX_3 "Message count requested for mailbox %s but voicemail not loaded.\n", mailbox);
00276 }
00277
00278 return 0;
00279 }
00280
00281 int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between)
00282 {
00283 char *ptr;
00284 int res = 0;
00285 struct ast_frame f;
00286 if (!between)
00287 between = 100;
00288
00289 if (peer)
00290 res = ast_autoservice_start(peer);
00291
00292 if (!res) {
00293 res = ast_waitfor(chan,100);
00294 if (res > -1) {
00295 for (ptr=digits; *ptr; ptr++) {
00296 if (*ptr == 'w') {
00297 res = ast_safe_sleep(chan, 500);
00298 if (res)
00299 break;
00300 continue;
00301 }
00302 memset(&f, 0, sizeof(f));
00303 f.frametype = AST_FRAME_DTMF;
00304 f.subclass = *ptr;
00305 f.src = "ast_dtmf_stream";
00306 if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
00307 ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
00308 } else {
00309 res = ast_write(chan, &f);
00310 if (res)
00311 break;
00312
00313 res = ast_safe_sleep(chan,between);
00314 if (res)
00315 break;
00316 }
00317 }
00318 }
00319 if (peer) {
00320
00321
00322 if (ast_autoservice_stop(peer) && !res)
00323 res = -1;
00324 }
00325 }
00326 return res;
00327 }
00328
00329 struct linear_state {
00330 int fd;
00331 int autoclose;
00332 int allowoverride;
00333 int origwfmt;
00334 };
00335
00336 static void linear_release(struct ast_channel *chan, void *params)
00337 {
00338 struct linear_state *ls = params;
00339 if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) {
00340 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt);
00341 }
00342 if (ls->autoclose)
00343 close(ls->fd);
00344 free(params);
00345 }
00346
00347 static int linear_generator(struct ast_channel *chan, void *data, int len, int samples)
00348 {
00349 struct ast_frame f;
00350 short buf[2048 + AST_FRIENDLY_OFFSET / 2];
00351 struct linear_state *ls = data;
00352 int res;
00353 len = samples * 2;
00354 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) {
00355 ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len);
00356 len = sizeof(buf) - AST_FRIENDLY_OFFSET;
00357 }
00358 memset(&f, 0, sizeof(f));
00359 res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len);
00360 if (res > 0) {
00361 f.frametype = AST_FRAME_VOICE;
00362 f.subclass = AST_FORMAT_SLINEAR;
00363 f.data = buf + AST_FRIENDLY_OFFSET/2;
00364 f.datalen = res;
00365 f.samples = res / 2;
00366 f.offset = AST_FRIENDLY_OFFSET;
00367 ast_write(chan, &f);
00368 if (res == len)
00369 return 0;
00370 }
00371 return -1;
00372 }
00373
00374 static void *linear_alloc(struct ast_channel *chan, void *params)
00375 {
00376 struct linear_state *ls;
00377
00378 if (params) {
00379 ls = params;
00380 if (ls->allowoverride)
00381 ast_set_flag(chan, AST_FLAG_WRITE_INT);
00382 else
00383 ast_clear_flag(chan, AST_FLAG_WRITE_INT);
00384 ls->origwfmt = chan->writeformat;
00385 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) {
00386 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name);
00387 free(ls);
00388 ls = params = NULL;
00389 }
00390 }
00391 return params;
00392 }
00393
00394 static struct ast_generator linearstream =
00395 {
00396 alloc: linear_alloc,
00397 release: linear_release,
00398 generate: linear_generator,
00399 };
00400
00401 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride)
00402 {
00403 struct linear_state *lin;
00404 char tmpf[256];
00405 int res = -1;
00406 int autoclose = 0;
00407 if (fd < 0) {
00408 if (ast_strlen_zero(filename))
00409 return -1;
00410 autoclose = 1;
00411 if (filename[0] == '/')
00412 ast_copy_string(tmpf, filename, sizeof(tmpf));
00413 else
00414 snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename);
00415 fd = open(tmpf, O_RDONLY);
00416 if (fd < 0){
00417 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno));
00418 return -1;
00419 }
00420 }
00421 lin = malloc(sizeof(struct linear_state));
00422 if (lin) {
00423 memset(lin, 0, sizeof(lin));
00424 lin->fd = fd;
00425 lin->allowoverride = allowoverride;
00426 lin->autoclose = autoclose;
00427 res = ast_activate_generator(chan, &linearstream, lin);
00428 }
00429 return res;
00430 }
00431
00432 int ast_control_streamfile(struct ast_channel *chan, const char *file,
00433 const char *fwd, const char *rev,
00434 const char *stop, const char *pause,
00435 const char *restart, int skipms)
00436 {
00437 char *breaks = NULL;
00438 char *end = NULL;
00439 int blen = 2;
00440 int res;
00441 long pause_restart_point = 0;
00442
00443 if (stop)
00444 blen += strlen(stop);
00445 if (pause)
00446 blen += strlen(pause);
00447 if (restart)
00448 blen += strlen(restart);
00449
00450 if (blen > 2) {
00451 breaks = alloca(blen + 1);
00452 breaks[0] = '\0';
00453 if (stop)
00454 strcat(breaks, stop);
00455 if (pause)
00456 strcat(breaks, pause);
00457 if (restart)
00458 strcat(breaks, restart);
00459 }
00460 if (chan->_state != AST_STATE_UP)
00461 res = ast_answer(chan);
00462
00463 if (file) {
00464 if ((end = strchr(file,':'))) {
00465 if (!strcasecmp(end, ":end")) {
00466 *end = '\0';
00467 end++;
00468 }
00469 }
00470 }
00471
00472 for (;;) {
00473 ast_stopstream(chan);
00474 res = ast_streamfile(chan, file, chan->language);
00475 if (!res) {
00476 if (pause_restart_point) {
00477 ast_seekstream(chan->stream, pause_restart_point, SEEK_SET);
00478 pause_restart_point = 0;
00479 }
00480 else if (end) {
00481 ast_seekstream(chan->stream, 0, SEEK_END);
00482 end = NULL;
00483 };
00484 res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms);
00485 }
00486
00487 if (res < 1)
00488 break;
00489
00490
00491 if (restart && strchr(restart, res)) {
00492 ast_log(LOG_DEBUG, "we'll restart the stream here at next loop\n");
00493 pause_restart_point = 0;
00494 continue;
00495 }
00496
00497 if (pause && strchr(pause, res)) {
00498 pause_restart_point = ast_tellstream(chan->stream);
00499 for (;;) {
00500 ast_stopstream(chan);
00501 res = ast_waitfordigit(chan, 1000);
00502 if (!res)
00503 continue;
00504 else if (res == -1 || strchr(pause, res) || (stop && strchr(stop, res)))
00505 break;
00506 }
00507 if (res == *pause) {
00508 res = 0;
00509 continue;
00510 }
00511 }
00512
00513 if (res == -1)
00514 break;
00515
00516
00517 if (stop && strchr(stop, res))
00518 break;
00519 }
00520
00521 ast_stopstream(chan);
00522
00523 return res;
00524 }
00525
00526 int ast_play_and_wait(struct ast_channel *chan, const char *fn)
00527 {
00528 int d;
00529 d = ast_streamfile(chan, fn, chan->language);
00530 if (d)
00531 return d;
00532 d = ast_waitstream(chan, AST_DIGIT_ANY);
00533 ast_stopstream(chan);
00534 return d;
00535 }
00536
00537 static int global_silence_threshold = 128;
00538 static int global_maxsilence = 0;
00539
00540 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)
00541 {
00542 int d;
00543 char *fmts;
00544 char comment[256];
00545 int x, fmtcnt=1, res=-1,outmsg=0;
00546 struct ast_frame *f;
00547 struct ast_filestream *others[MAX_OTHER_FORMATS];
00548 char *sfmt[MAX_OTHER_FORMATS];
00549 char *stringp=NULL;
00550 time_t start, end;
00551 struct ast_dsp *sildet=NULL;
00552 int totalsilence = 0;
00553 int dspsilence = 0;
00554 int rfmt=0;
00555 struct ast_silence_generator *silgen = NULL;
00556
00557 if (silencethreshold < 0)
00558 silencethreshold = global_silence_threshold;
00559
00560 if (maxsilence < 0)
00561 maxsilence = global_maxsilence;
00562
00563
00564 if (duration == NULL) {
00565 ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00566 return -1;
00567 }
00568
00569 ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00570 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00571
00572 if (playfile) {
00573 d = ast_play_and_wait(chan, playfile);
00574 if (d > -1)
00575 d = ast_streamfile(chan, "beep",chan->language);
00576 if (!d)
00577 d = ast_waitstream(chan,"");
00578 if (d < 0)
00579 return -1;
00580 }
00581
00582 fmts = ast_strdupa(fmt);
00583
00584 stringp=fmts;
00585 strsep(&stringp, "|");
00586 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00587 sfmt[0] = ast_strdupa(fmts);
00588
00589 while((fmt = strsep(&stringp, "|"))) {
00590 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00591 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
00592 break;
00593 }
00594 sfmt[fmtcnt++] = ast_strdupa(fmt);
00595 }
00596
00597 time(&start);
00598 end=start;
00599 for (x=0;x<fmtcnt;x++) {
00600 others[x] = ast_writefile(recordfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00601 ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, recordfile, sfmt[x], others[x]);
00602
00603 if (!others[x]) {
00604 break;
00605 }
00606 }
00607
00608 if (path)
00609 ast_unlock_path(path);
00610
00611 if (maxsilence > 0) {
00612 sildet = ast_dsp_new();
00613 if (!sildet) {
00614 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00615 return -1;
00616 }
00617 ast_dsp_set_threshold(sildet, silencethreshold);
00618 rfmt = chan->readformat;
00619 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00620 if (res < 0) {
00621 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00622 ast_dsp_free(sildet);
00623 return -1;
00624 }
00625 }
00626
00627
00628 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00629
00630 if (option_transmit_silence_during_record)
00631 silgen = ast_channel_start_silence_generator(chan);
00632
00633 if (x == fmtcnt) {
00634
00635
00636 f = NULL;
00637 for(;;) {
00638 res = ast_waitfor(chan, 2000);
00639 if (!res) {
00640 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00641
00642 res = ast_waitfor(chan, 2000);
00643 if (!res) {
00644 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00645 res = -1;
00646 }
00647 }
00648
00649 if (res < 0) {
00650 f = NULL;
00651 break;
00652 }
00653 f = ast_read(chan);
00654 if (!f)
00655 break;
00656 if (f->frametype == AST_FRAME_VOICE) {
00657
00658 for (x=0;x<fmtcnt;x++) {
00659 res = ast_writestream(others[x], f);
00660 }
00661
00662
00663 if (maxsilence > 0) {
00664 dspsilence = 0;
00665 ast_dsp_silence(sildet, f, &dspsilence);
00666 if (dspsilence)
00667 totalsilence = dspsilence;
00668 else
00669 totalsilence = 0;
00670
00671 if (totalsilence > maxsilence) {
00672
00673 if (option_verbose > 2)
00674 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00675 ast_frfree(f);
00676 res = 'S';
00677 outmsg=2;
00678 break;
00679 }
00680 }
00681
00682 if (res) {
00683 ast_log(LOG_WARNING, "Error writing frame\n");
00684 ast_frfree(f);
00685 break;
00686 }
00687 } else if (f->frametype == AST_FRAME_VIDEO) {
00688
00689 ast_writestream(others[0], f);
00690 } else if (f->frametype == AST_FRAME_DTMF) {
00691 if (strchr(acceptdtmf, f->subclass)) {
00692 if (option_verbose > 2)
00693 ast_verbose(VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00694 res = f->subclass;
00695 outmsg = 2;
00696 ast_frfree(f);
00697 break;
00698 }
00699 if (strchr(canceldtmf, f->subclass)) {
00700 if (option_verbose > 2)
00701 ast_verbose(VERBOSE_PREFIX_3 "User cancelled message by pressing %c\n", f->subclass);
00702 res = f->subclass;
00703 outmsg = 0;
00704 ast_frfree(f);
00705 break;
00706 }
00707 }
00708 if (maxtime) {
00709 time(&end);
00710 if (maxtime < (end - start)) {
00711 if (option_verbose > 2)
00712 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00713 outmsg = 2;
00714 res = 't';
00715 ast_frfree(f);
00716 break;
00717 }
00718 }
00719 ast_frfree(f);
00720 }
00721 if (end == start) time(&end);
00722 if (!f) {
00723 if (option_verbose > 2)
00724 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00725 res = -1;
00726 outmsg=1;
00727 }
00728 } else {
00729 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00730 }
00731
00732 if (silgen)
00733 ast_channel_stop_silence_generator(chan, silgen);
00734
00735 *duration = end - start;
00736
00737 for (x=0;x<fmtcnt;x++) {
00738 if (!others[x])
00739 break;
00740 if (res > 0) {
00741 if (totalsilence)
00742 ast_stream_rewind(others[x], totalsilence-200);
00743 else
00744 ast_stream_rewind(others[x], 200);
00745 }
00746 ast_truncstream(others[x]);
00747 ast_closestream(others[x]);
00748 }
00749 if (rfmt) {
00750 if (ast_set_read_format(chan, rfmt)) {
00751 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00752 }
00753 }
00754 if (outmsg > 1) {
00755
00756 if(!ast_streamfile(chan, "auth-thankyou", chan->language))
00757 ast_waitstream(chan, "");
00758 }
00759 if (sildet)
00760 ast_dsp_free(sildet);
00761 return res;
00762 }
00763
00764 static char default_acceptdtmf[] = "#";
00765 static char default_canceldtmf[] = "0";
00766
00767 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)
00768 {
00769 return ast_play_and_record_full(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path, default_acceptdtmf, default_canceldtmf);
00770 }
00771
00772 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)
00773 {
00774 int d = 0;
00775 char *fmts;
00776 char comment[256];
00777 int x, fmtcnt=1, res=-1,outmsg=0;
00778 struct ast_frame *f;
00779 struct ast_filestream *others[MAX_OTHER_FORMATS];
00780 struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
00781 char *sfmt[MAX_OTHER_FORMATS];
00782 char *stringp=NULL;
00783 time_t start, end;
00784 struct ast_dsp *sildet;
00785 int totalsilence = 0;
00786 int dspsilence = 0;
00787 int rfmt=0;
00788 char prependfile[80];
00789
00790 if (silencethreshold < 0)
00791 silencethreshold = global_silence_threshold;
00792
00793 if (maxsilence < 0)
00794 maxsilence = global_maxsilence;
00795
00796
00797 if (duration == NULL) {
00798 ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
00799 return -1;
00800 }
00801
00802 ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00803 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00804
00805 if (playfile || beep) {
00806 if (!beep)
00807 d = ast_play_and_wait(chan, playfile);
00808 if (d > -1)
00809 d = ast_streamfile(chan, "beep",chan->language);
00810 if (!d)
00811 d = ast_waitstream(chan,"");
00812 if (d < 0)
00813 return -1;
00814 }
00815 ast_copy_string(prependfile, recordfile, sizeof(prependfile));
00816 strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00817
00818 fmts = ast_strdupa(fmt);
00819
00820 stringp=fmts;
00821 strsep(&stringp, "|");
00822 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00823 sfmt[0] = ast_strdupa(fmts);
00824
00825 while((fmt = strsep(&stringp, "|"))) {
00826 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00827 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
00828 break;
00829 }
00830 sfmt[fmtcnt++] = ast_strdupa(fmt);
00831 }
00832
00833 time(&start);
00834 end=start;
00835 for (x=0;x<fmtcnt;x++) {
00836 others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00837 ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
00838 if (!others[x]) {
00839 break;
00840 }
00841 }
00842
00843 sildet = ast_dsp_new();
00844 if (!sildet) {
00845 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00846 return -1;
00847 }
00848 ast_dsp_set_threshold(sildet, silencethreshold);
00849
00850 if (maxsilence > 0) {
00851 rfmt = chan->readformat;
00852 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00853 if (res < 0) {
00854 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00855 ast_dsp_free(sildet);
00856 return -1;
00857 }
00858 }
00859
00860 if (x == fmtcnt) {
00861
00862
00863 f = NULL;
00864 for(;;) {
00865 res = ast_waitfor(chan, 2000);
00866 if (!res) {
00867 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00868
00869 res = ast_waitfor(chan, 2000);
00870 if (!res) {
00871 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00872 res = -1;
00873 }
00874 }
00875
00876 if (res < 0) {
00877 f = NULL;
00878 break;
00879 }
00880 f = ast_read(chan);
00881 if (!f)
00882 break;
00883 if (f->frametype == AST_FRAME_VOICE) {
00884
00885 for (x=0;x<fmtcnt;x++) {
00886 if (!others[x])
00887 break;
00888 res = ast_writestream(others[x], f);
00889 }
00890
00891
00892 if (maxsilence > 0) {
00893 dspsilence = 0;
00894 ast_dsp_silence(sildet, f, &dspsilence);
00895 if (dspsilence)
00896 totalsilence = dspsilence;
00897 else
00898 totalsilence = 0;
00899
00900 if (totalsilence > maxsilence) {
00901
00902 if (option_verbose > 2)
00903 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00904 ast_frfree(f);
00905 res = 'S';
00906 outmsg=2;
00907 break;
00908 }
00909 }
00910
00911 if (res) {
00912 ast_log(LOG_WARNING, "Error writing frame\n");
00913 ast_frfree(f);
00914 break;
00915 }
00916 } else if (f->frametype == AST_FRAME_VIDEO) {
00917
00918 ast_writestream(others[0], f);
00919 } else if (f->frametype == AST_FRAME_DTMF) {
00920
00921 if (option_verbose > 2)
00922 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00923 res = 't';
00924 outmsg = 2;
00925 ast_frfree(f);
00926 break;
00927 }
00928 if (maxtime) {
00929 time(&end);
00930 if (maxtime < (end - start)) {
00931 if (option_verbose > 2)
00932 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00933 res = 't';
00934 outmsg=2;
00935 ast_frfree(f);
00936 break;
00937 }
00938 }
00939 ast_frfree(f);
00940 }
00941 if (end == start) time(&end);
00942 if (!f) {
00943 if (option_verbose > 2)
00944 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00945 res = -1;
00946 outmsg=1;
00947 #if 0
00948
00949 for (x=0;x<fmtcnt;x++) {
00950 if (!others[x])
00951 break;
00952 ast_closestream(others[x]);
00953 ast_filedelete(prependfile, sfmt[x]);
00954 }
00955 #endif
00956 }
00957 } else {
00958 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
00959 }
00960 ast_dsp_free(sildet);
00961 *duration = end - start;
00962 #if 0
00963 if (outmsg > 1) {
00964 #else
00965 if (outmsg) {
00966 #endif
00967 struct ast_frame *fr;
00968 for (x=0;x<fmtcnt;x++) {
00969 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
00970 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00971 if (!others[x] || !realfiles[x])
00972 break;
00973 if (totalsilence)
00974 ast_stream_rewind(others[x], totalsilence-200);
00975 else
00976 ast_stream_rewind(others[x], 200);
00977 ast_truncstream(others[x]);
00978
00979 while ((fr = ast_readframe(realfiles[x]))) {
00980 ast_writestream(others[x],fr);
00981 }
00982 ast_closestream(others[x]);
00983 ast_closestream(realfiles[x]);
00984 ast_filerename(prependfile, recordfile, sfmt[x]);
00985 #if 0
00986 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
00987 #endif
00988 ast_filedelete(prependfile, sfmt[x]);
00989 }
00990 }
00991 if (rfmt) {
00992 if (ast_set_read_format(chan, rfmt)) {
00993 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00994 }
00995 }
00996 if (outmsg) {
00997 if (outmsg > 1) {
00998
00999 ast_streamfile(chan, "auth-thankyou", chan->language);
01000 ast_waitstream(chan, "");
01001 }
01002 }
01003 return res;
01004 }
01005
01006
01007
01008 int ast_app_group_split_group(char *data, char *group, int group_max, char *category, int category_max)
01009 {
01010 int res=0;
01011 char tmp[256];
01012 char *grp=NULL, *cat=NULL;
01013
01014 if (!ast_strlen_zero(data)) {
01015 ast_copy_string(tmp, data, sizeof(tmp));
01016 grp = tmp;
01017 cat = strchr(tmp, '@');
01018 if (cat) {
01019 *cat = '\0';
01020 cat++;
01021 }
01022 }
01023
01024 if (!ast_strlen_zero(grp))
01025 ast_copy_string(group, grp, group_max);
01026 else
01027 res = -1;
01028
01029 if (cat)
01030 snprintf(category, category_max, "%s_%s", GROUP_CATEGORY_PREFIX, cat);
01031 else
01032 ast_copy_string(category, GROUP_CATEGORY_PREFIX, category_max);
01033
01034 return res;
01035 }
01036
01037 int ast_app_group_set_channel(struct ast_channel *chan, char *data)
01038 {
01039 int res=0;
01040 char group[80] = "";
01041 char category[80] = "";
01042
01043 if (!ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
01044 pbx_builtin_setvar_helper(chan, category, group);
01045 } else
01046 res = -1;
01047
01048 return res;
01049 }
01050
01051 int ast_app_group_get_count(char *group, char *category)
01052 {
01053 struct ast_channel *chan;
01054 int count = 0;
01055 char *test;
01056 char cat[80];
01057 char *s;
01058
01059 if (ast_strlen_zero(group))
01060 return 0;
01061
01062 s = (!ast_strlen_zero(category)) ? category : GROUP_CATEGORY_PREFIX;
01063 ast_copy_string(cat, s, sizeof(cat));
01064
01065 chan = NULL;
01066 while ((chan = ast_channel_walk_locked(chan)) != NULL) {
01067 test = pbx_builtin_getvar_helper(chan, cat);
01068 if (test && !strcasecmp(test, group))
01069 count++;
01070 ast_mutex_unlock(&chan->lock);
01071 }
01072
01073 return count;
01074 }
01075
01076 int ast_app_group_match_get_count(char *groupmatch, char *category)
01077 {
01078 regex_t regexbuf;
01079 struct ast_channel *chan;
01080 int count = 0;
01081 char *test;
01082 char cat[80];
01083 char *s;
01084
01085 if (ast_strlen_zero(groupmatch))
01086 return 0;
01087
01088
01089 if (regcomp(®exbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
01090 return 0;
01091
01092 s = (!ast_strlen_zero(category)) ? category : GROUP_CATEGORY_PREFIX;
01093 ast_copy_string(cat, s, sizeof(cat));
01094
01095 chan = NULL;
01096 while ((chan = ast_channel_walk_locked(chan)) != NULL) {
01097 test = pbx_builtin_getvar_helper(chan, cat);
01098 if (test && !regexec(®exbuf, test, 0, NULL, 0))
01099 count++;
01100 ast_mutex_unlock(&chan->lock);
01101 }
01102
01103 regfree(®exbuf);
01104
01105 return count;
01106 }
01107
01108 unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
01109 {
01110 int argc;
01111 char *scan;
01112 int paren = 0;
01113
01114 if (!buf || !array || !arraylen)
01115 return 0;
01116
01117 memset(array, 0, arraylen * sizeof(*array));
01118
01119 scan = buf;
01120
01121 for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
01122 array[argc] = scan;
01123 for (; *scan; scan++) {
01124 if (*scan == '(')
01125 paren++;
01126 else if (*scan == ')') {
01127 if (paren)
01128 paren--;
01129 } else if ((*scan == delim) && !paren) {
01130 *scan++ = '\0';
01131 break;
01132 }
01133 }
01134 }
01135
01136 if (*scan)
01137 array[argc++] = scan;
01138
01139 return argc;
01140 }
01141
01142 enum AST_LOCK_RESULT ast_lock_path(const char *path)
01143 {
01144 char *s;
01145 char *fs;
01146 int res;
01147 int fd;
01148 time_t start;
01149
01150 s = alloca(strlen(path) + 10);
01151 fs = alloca(strlen(path) + 20);
01152
01153 if (!fs || !s) {
01154 ast_log(LOG_WARNING, "Out of memory!\n");
01155 return AST_LOCK_FAILURE;
01156 }
01157
01158 snprintf(fs, strlen(path) + 19, "%s/.lock-%08x", path, rand());
01159 fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
01160 if (fd < 0) {
01161 ast_log(LOG_ERROR, "Unable to create lock file '%s': %s\n", path, strerror(errno));
01162 return AST_LOCK_PATH_NOT_FOUND;
01163 }
01164 close(fd);
01165
01166 snprintf(s, strlen(path) + 9, "%s/.lock", path);
01167 time(&start);
01168 while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
01169 usleep(1);
01170
01171 unlink(fs);
01172
01173 if (res) {
01174 ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
01175 return AST_LOCK_TIMEOUT;
01176 } else {
01177 ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
01178 return AST_LOCK_SUCCESS;
01179 }
01180 }
01181
01182 int ast_unlock_path(const char *path)
01183 {
01184 char *s;
01185 int res;
01186
01187 s = alloca(strlen(path) + 10);
01188 if (!s) {
01189 ast_log(LOG_WARNING, "Out of memory!\n");
01190 return -1;
01191 }
01192
01193 snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01194
01195 if ((res = unlink(s)))
01196 ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
01197 else
01198 ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01199
01200 return res;
01201 }
01202
01203 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
01204 {
01205 int silencethreshold = 128;
01206 int maxsilence=0;
01207 int res = 0;
01208 int cmd = 0;
01209 int max_attempts = 3;
01210 int attempts = 0;
01211 int recorded = 0;
01212 int message_exists = 0;
01213
01214
01215
01216 if (duration == NULL) {
01217 ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
01218 return -1;
01219 }
01220
01221 cmd = '3';
01222
01223 while ((cmd >= 0) && (cmd != 't')) {
01224 switch (cmd) {
01225 case '1':
01226 if (!message_exists) {
01227
01228 cmd = '3';
01229 break;
01230 } else {
01231 ast_streamfile(chan, "vm-msgsaved", chan->language);
01232 ast_waitstream(chan, "");
01233 cmd = 't';
01234 return res;
01235 }
01236 case '2':
01237
01238 ast_verbose(VERBOSE_PREFIX_3 "Reviewing the recording\n");
01239 ast_streamfile(chan, recordfile, chan->language);
01240 cmd = ast_waitstream(chan, AST_DIGIT_ANY);
01241 break;
01242 case '3':
01243 message_exists = 0;
01244
01245 if (recorded == 1)
01246 ast_verbose(VERBOSE_PREFIX_3 "Re-recording\n");
01247 else
01248 ast_verbose(VERBOSE_PREFIX_3 "Recording\n");
01249 recorded = 1;
01250 cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path);
01251 if (cmd == -1) {
01252
01253 return cmd;
01254 }
01255 if (cmd == '0') {
01256 break;
01257 } else if (cmd == '*') {
01258 break;
01259 }
01260 else {
01261
01262 message_exists = 1;
01263 cmd = 0;
01264 }
01265 break;
01266 case '4':
01267 case '5':
01268 case '6':
01269 case '7':
01270 case '8':
01271 case '9':
01272 case '*':
01273 case '#':
01274 cmd = ast_play_and_wait(chan, "vm-sorry");
01275 break;
01276 default:
01277 if (message_exists) {
01278 cmd = ast_play_and_wait(chan, "vm-review");
01279 }
01280 else {
01281 cmd = ast_play_and_wait(chan, "vm-torerecord");
01282 if (!cmd)
01283 cmd = ast_waitfordigit(chan, 600);
01284 }
01285
01286 if (!cmd)
01287 cmd = ast_waitfordigit(chan, 6000);
01288 if (!cmd) {
01289 attempts++;
01290 }
01291 if (attempts > max_attempts) {
01292 cmd = 't';
01293 }
01294 }
01295 }
01296 if (cmd == 't')
01297 cmd = 0;
01298 return cmd;
01299 }
01300
01301 #define RES_UPONE (1 << 16)
01302 #define RES_EXIT (1 << 17)
01303 #define RES_REPEAT (1 << 18)
01304 #define RES_RESTART ((1 << 19) | RES_REPEAT)
01305
01306 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
01307 static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
01308 {
01309 int res;
01310 int (*ivr_func)(struct ast_channel *, void *);
01311 char *c;
01312 char *n;
01313
01314 switch(option->action) {
01315 case AST_ACTION_UPONE:
01316 return RES_UPONE;
01317 case AST_ACTION_EXIT:
01318 return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
01319 case AST_ACTION_REPEAT:
01320 return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
01321 case AST_ACTION_RESTART:
01322 return RES_RESTART ;
01323 case AST_ACTION_NOOP:
01324 return 0;
01325 case AST_ACTION_BACKGROUND:
01326 res = ast_streamfile(chan, (char *)option->adata, chan->language);
01327 if (!res) {
01328 res = ast_waitstream(chan, AST_DIGIT_ANY);
01329 } else {
01330 ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01331 res = 0;
01332 }
01333 return res;
01334 case AST_ACTION_PLAYBACK:
01335 res = ast_streamfile(chan, (char *)option->adata, chan->language);
01336 if (!res) {
01337 res = ast_waitstream(chan, "");
01338 } else {
01339 ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01340 res = 0;
01341 }
01342 return res;
01343 case AST_ACTION_MENU:
01344 res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata);
01345
01346 if (res == -2)
01347 res = 0;
01348 return res;
01349 case AST_ACTION_WAITOPTION:
01350 res = ast_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10));
01351 if (!res)
01352 return 't';
01353 return res;
01354 case AST_ACTION_CALLBACK:
01355 ivr_func = option->adata;
01356 res = ivr_func(chan, cbdata);
01357 return res;
01358 case AST_ACTION_TRANSFER:
01359 res = ast_parseable_goto(chan, option->adata);
01360 return 0;
01361 case AST_ACTION_PLAYLIST:
01362 case AST_ACTION_BACKLIST:
01363 res = 0;
01364 c = ast_strdupa(option->adata);
01365 if (c) {
01366 while((n = strsep(&c, ";")))
01367 if ((res = ast_streamfile(chan, n, chan->language)) || (res = ast_waitstream(chan, (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
01368 break;
01369 ast_stopstream(chan);
01370 }
01371 return res;
01372 default:
01373 ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
01374 return 0;
01375 };
01376 return -1;
01377 }
01378
01379 static int option_exists(struct ast_ivr_menu *menu, char *option)
01380 {
01381 int x;
01382 for (x=0;menu->options[x].option;x++)
01383 if (!strcasecmp(menu->options[x].option, option))
01384 return x;
01385 return -1;
01386 }
01387
01388 static int option_matchmore(struct ast_ivr_menu *menu, char *option)
01389 {
01390 int x;
01391 for (x=0;menu->options[x].option;x++)
01392 if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
01393 (menu->options[x].option[strlen(option)]))
01394 return x;
01395 return -1;
01396 }
01397
01398 static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
01399 {
01400 int res=0;
01401 int ms;
01402 while(option_matchmore(menu, exten)) {
01403 ms = chan->pbx ? chan->pbx->dtimeout : 5000;
01404 if (strlen(exten) >= maxexten - 1)
01405 break;
01406 res = ast_waitfordigit(chan, ms);
01407 if (res < 1)
01408 break;
01409 exten[strlen(exten) + 1] = '\0';
01410 exten[strlen(exten)] = res;
01411 }
01412 return res > 0 ? 0 : res;
01413 }
01414
01415 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01416 {
01417
01418 int res=0;
01419 int pos = 0;
01420 int retries = 0;
01421 char exten[AST_MAX_EXTENSION] = "s";
01422 if (option_exists(menu, "s") < 0) {
01423 strcpy(exten, "g");
01424 if (option_exists(menu, "g") < 0) {
01425 ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
01426 return -1;
01427 }
01428 }
01429 while(!res) {
01430 while(menu->options[pos].option) {
01431 if (!strcasecmp(menu->options[pos].option, exten)) {
01432 res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
01433 ast_log(LOG_DEBUG, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
01434 if (res < 0)
01435 break;
01436 else if (res & RES_UPONE)
01437 return 0;
01438 else if (res & RES_EXIT)
01439 return res;
01440 else if (res & RES_REPEAT) {
01441 int maxretries = res & 0xffff;
01442 if ((res & RES_RESTART) == RES_RESTART) {
01443 retries = 0;
01444 } else
01445 retries++;
01446 if (!maxretries)
01447 maxretries = 3;
01448 if ((maxretries > 0) && (retries >= maxretries)) {
01449 ast_log(LOG_DEBUG, "Max retries %d exceeded\n", maxretries);
01450 return -2;
01451 } else {
01452 if (option_exists(menu, "g") > -1)
01453 strcpy(exten, "g");
01454 else if (option_exists(menu, "s") > -1)
01455 strcpy(exten, "s");
01456 }
01457 pos=0;
01458 continue;
01459 } else if (res && strchr(AST_DIGIT_ANY, res)) {
01460 ast_log(LOG_DEBUG, "Got start of extension, %c\n", res);
01461 exten[1] = '\0';
01462 exten[0] = res;
01463 if ((res = read_newoption(chan, menu, exten, sizeof(exten))))
01464 break;
01465 if (option_exists(menu, exten) < 0) {
01466 if (option_exists(menu, "i")) {
01467 ast_log(LOG_DEBUG, "Invalid extension entered, going to 'i'!\n");
01468 strcpy(exten, "i");
01469 pos = 0;
01470 continue;
01471 } else {
01472 ast_log(LOG_DEBUG, "Aborting on invalid entry, with no 'i' option!\n");
01473 res = -2;
01474 break;
01475 }
01476 } else {
01477 ast_log(LOG_DEBUG, "New existing extension: %s\n", exten);
01478 pos = 0;
01479 continue;
01480 }
01481 }
01482 }
01483 pos++;
01484 }
01485 ast_log(LOG_DEBUG, "Stopping option '%s', res is %d\n", exten, res);
01486 pos = 0;
01487 if (!strcasecmp(exten, "s"))
01488 strcpy(exten, "g");
01489 else
01490 break;
01491 }
01492 return res;
01493 }
01494
01495 int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01496 {
01497 int res;
01498 res = ast_ivr_menu_run_internal(chan, menu, cbdata);
01499
01500 if (res > 0)
01501 res = 0;
01502 return res;
01503 }
01504
01505 char *ast_read_textfile(const char *filename)
01506 {
01507 int fd;
01508 char *output=NULL;
01509 struct stat filesize;
01510 int count=0;
01511 int res;
01512 if(stat(filename,&filesize)== -1){
01513 ast_log(LOG_WARNING,"Error can't stat %s\n", filename);
01514 return NULL;
01515 }
01516 count=filesize.st_size + 1;
01517 fd = open(filename, O_RDONLY);
01518 if (fd < 0) {
01519 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
01520 return NULL;
01521 }
01522 output=(char *)malloc(count);
01523 if (output) {
01524 res = read(fd, output, count - 1);
01525 if (res == count - 1) {
01526 output[res] = '\0';
01527 } else {
01528 ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
01529 free(output);
01530 output = NULL;
01531 }
01532 } else
01533 ast_log(LOG_WARNING, "Out of memory!\n");
01534 close(fd);
01535 return output;
01536 }
01537
01538 int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
01539 {
01540 char *s;
01541 int curarg;
01542 unsigned int argloc;
01543 char *arg;
01544 int res = 0;
01545
01546 ast_clear_flag(flags, AST_FLAGS_ALL);
01547
01548 if (!optstr)
01549 return 0;
01550
01551 s = optstr;
01552 while (*s) {
01553 curarg = *s++ & 0x7f;
01554 ast_set_flag(flags, options[curarg].flag);
01555 argloc = options[curarg].arg_index;
01556 if (*s == '(') {
01557
01558 arg = ++s;
01559 while (*s && (*s != ')'))
01560 s++;
01561 if (*s) {
01562 if (argloc)
01563 args[argloc - 1] = arg;
01564 *s++ = '\0';
01565 } else {
01566 ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
01567 res = -1;
01568 }
01569 } else if (argloc) {
01570 args[argloc - 1] = NULL;
01571 }
01572 }
01573
01574 return res;
01575 }