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: 19008 $")
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(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, int silencethreshold, int maxsilence, const char *path)
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 (f->subclass == '#') {
00692 if (option_verbose > 2)
00693 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00694 res = '#';
00695 outmsg = 2;
00696 ast_frfree(f);
00697 break;
00698 }
00699 if (f->subclass == '0') {
00700
00701 if (option_verbose > 2)
00702 ast_verbose(VERBOSE_PREFIX_3 "User cancelled by pressing %c\n", f->subclass);
00703 res = '0';
00704 outmsg = 0;
00705 ast_frfree(f);
00706 break;
00707 }
00708 }
00709 if (maxtime) {
00710 time(&end);
00711 if (maxtime < (end - start)) {
00712 if (option_verbose > 2)
00713 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00714 outmsg = 2;
00715 res = 't';
00716 ast_frfree(f);
00717 break;
00718 }
00719 }
00720 ast_frfree(f);
00721 }
00722 if (end == start) time(&end);
00723 if (!f) {
00724 if (option_verbose > 2)
00725 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00726 res = -1;
00727 outmsg=1;
00728 }
00729 } else {
00730 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00731 }
00732
00733 if (silgen)
00734 ast_channel_stop_silence_generator(chan, silgen);
00735
00736 *duration = end - start;
00737
00738 for (x=0;x<fmtcnt;x++) {
00739 if (!others[x])
00740 break;
00741 if (res > 0) {
00742 if (totalsilence)
00743 ast_stream_rewind(others[x], totalsilence-200);
00744 else
00745 ast_stream_rewind(others[x], 200);
00746 }
00747 ast_truncstream(others[x]);
00748 ast_closestream(others[x]);
00749 }
00750 if (rfmt) {
00751 if (ast_set_read_format(chan, rfmt)) {
00752 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00753 }
00754 }
00755 if (outmsg > 1) {
00756
00757 if(!ast_streamfile(chan, "auth-thankyou", chan->language))
00758 ast_waitstream(chan, "");
00759 }
00760 if (sildet)
00761 ast_dsp_free(sildet);
00762 return res;
00763 }
00764
00765 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)
00766 {
00767 int d = 0;
00768 char *fmts;
00769 char comment[256];
00770 int x, fmtcnt=1, res=-1,outmsg=0;
00771 struct ast_frame *f;
00772 struct ast_filestream *others[MAX_OTHER_FORMATS];
00773 struct ast_filestream *realfiles[MAX_OTHER_FORMATS];
00774 char *sfmt[MAX_OTHER_FORMATS];
00775 char *stringp=NULL;
00776 time_t start, end;
00777 struct ast_dsp *sildet;
00778 int totalsilence = 0;
00779 int dspsilence = 0;
00780 int rfmt=0;
00781 char prependfile[80];
00782
00783 if (silencethreshold < 0)
00784 silencethreshold = global_silence_threshold;
00785
00786 if (maxsilence < 0)
00787 maxsilence = global_maxsilence;
00788
00789
00790 if (duration == NULL) {
00791 ast_log(LOG_WARNING, "Error play_and_prepend called without duration pointer\n");
00792 return -1;
00793 }
00794
00795 ast_log(LOG_DEBUG,"play_and_prepend: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00796 snprintf(comment,sizeof(comment),"Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00797
00798 if (playfile || beep) {
00799 if (!beep)
00800 d = ast_play_and_wait(chan, playfile);
00801 if (d > -1)
00802 d = ast_streamfile(chan, "beep",chan->language);
00803 if (!d)
00804 d = ast_waitstream(chan,"");
00805 if (d < 0)
00806 return -1;
00807 }
00808 ast_copy_string(prependfile, recordfile, sizeof(prependfile));
00809 strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00810
00811 fmts = ast_strdupa(fmt);
00812
00813 stringp=fmts;
00814 strsep(&stringp, "|");
00815 ast_log(LOG_DEBUG,"Recording Formats: sfmts=%s\n", fmts);
00816 sfmt[0] = ast_strdupa(fmts);
00817
00818 while((fmt = strsep(&stringp, "|"))) {
00819 if (fmtcnt > MAX_OTHER_FORMATS - 1) {
00820 ast_log(LOG_WARNING, "Please increase MAX_OTHER_FORMATS in app.c\n");
00821 break;
00822 }
00823 sfmt[fmtcnt++] = ast_strdupa(fmt);
00824 }
00825
00826 time(&start);
00827 end=start;
00828 for (x=0;x<fmtcnt;x++) {
00829 others[x] = ast_writefile(prependfile, sfmt[x], comment, O_TRUNC, 0, 0700);
00830 ast_verbose( VERBOSE_PREFIX_3 "x=%d, open writing: %s format: %s, %p\n", x, prependfile, sfmt[x], others[x]);
00831 if (!others[x]) {
00832 break;
00833 }
00834 }
00835
00836 sildet = ast_dsp_new();
00837 if (!sildet) {
00838 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00839 return -1;
00840 }
00841 ast_dsp_set_threshold(sildet, silencethreshold);
00842
00843 if (maxsilence > 0) {
00844 rfmt = chan->readformat;
00845 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00846 if (res < 0) {
00847 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00848 ast_dsp_free(sildet);
00849 return -1;
00850 }
00851 }
00852
00853 if (x == fmtcnt) {
00854
00855
00856 f = NULL;
00857 for(;;) {
00858 res = ast_waitfor(chan, 2000);
00859 if (!res) {
00860 ast_log(LOG_DEBUG, "One waitfor failed, trying another\n");
00861
00862 res = ast_waitfor(chan, 2000);
00863 if (!res) {
00864 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00865 res = -1;
00866 }
00867 }
00868
00869 if (res < 0) {
00870 f = NULL;
00871 break;
00872 }
00873 f = ast_read(chan);
00874 if (!f)
00875 break;
00876 if (f->frametype == AST_FRAME_VOICE) {
00877
00878 for (x=0;x<fmtcnt;x++) {
00879 if (!others[x])
00880 break;
00881 res = ast_writestream(others[x], f);
00882 }
00883
00884
00885 if (maxsilence > 0) {
00886 dspsilence = 0;
00887 ast_dsp_silence(sildet, f, &dspsilence);
00888 if (dspsilence)
00889 totalsilence = dspsilence;
00890 else
00891 totalsilence = 0;
00892
00893 if (totalsilence > maxsilence) {
00894
00895 if (option_verbose > 2)
00896 ast_verbose( VERBOSE_PREFIX_3 "Recording automatically stopped after a silence of %d seconds\n", totalsilence/1000);
00897 ast_frfree(f);
00898 res = 'S';
00899 outmsg=2;
00900 break;
00901 }
00902 }
00903
00904 if (res) {
00905 ast_log(LOG_WARNING, "Error writing frame\n");
00906 ast_frfree(f);
00907 break;
00908 }
00909 } else if (f->frametype == AST_FRAME_VIDEO) {
00910
00911 ast_writestream(others[0], f);
00912 } else if (f->frametype == AST_FRAME_DTMF) {
00913
00914 if (option_verbose > 2)
00915 ast_verbose( VERBOSE_PREFIX_3 "User ended message by pressing %c\n", f->subclass);
00916 res = 't';
00917 outmsg = 2;
00918 ast_frfree(f);
00919 break;
00920 }
00921 if (maxtime) {
00922 time(&end);
00923 if (maxtime < (end - start)) {
00924 if (option_verbose > 2)
00925 ast_verbose( VERBOSE_PREFIX_3 "Took too long, cutting it short...\n");
00926 res = 't';
00927 outmsg=2;
00928 ast_frfree(f);
00929 break;
00930 }
00931 }
00932 ast_frfree(f);
00933 }
00934 if (end == start) time(&end);
00935 if (!f) {
00936 if (option_verbose > 2)
00937 ast_verbose( VERBOSE_PREFIX_3 "User hung up\n");
00938 res = -1;
00939 outmsg=1;
00940 #if 0
00941
00942 for (x=0;x<fmtcnt;x++) {
00943 if (!others[x])
00944 break;
00945 ast_closestream(others[x]);
00946 ast_filedelete(prependfile, sfmt[x]);
00947 }
00948 #endif
00949 }
00950 } else {
00951 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", prependfile, sfmt[x]);
00952 }
00953 ast_dsp_free(sildet);
00954 *duration = end - start;
00955 #if 0
00956 if (outmsg > 1) {
00957 #else
00958 if (outmsg) {
00959 #endif
00960 struct ast_frame *fr;
00961 for (x=0;x<fmtcnt;x++) {
00962 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
00963 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
00964 if (!others[x] || !realfiles[x])
00965 break;
00966 if (totalsilence)
00967 ast_stream_rewind(others[x], totalsilence-200);
00968 else
00969 ast_stream_rewind(others[x], 200);
00970 ast_truncstream(others[x]);
00971
00972 while ((fr = ast_readframe(realfiles[x]))) {
00973 ast_writestream(others[x],fr);
00974 }
00975 ast_closestream(others[x]);
00976 ast_closestream(realfiles[x]);
00977 ast_filerename(prependfile, recordfile, sfmt[x]);
00978 #if 0
00979 ast_verbose("Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x],prependfile,recordfile);
00980 #endif
00981 ast_filedelete(prependfile, sfmt[x]);
00982 }
00983 }
00984 if (rfmt) {
00985 if (ast_set_read_format(chan, rfmt)) {
00986 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
00987 }
00988 }
00989 if (outmsg) {
00990 if (outmsg > 1) {
00991
00992 ast_streamfile(chan, "auth-thankyou", chan->language);
00993 ast_waitstream(chan, "");
00994 }
00995 }
00996 return res;
00997 }
00998
00999
01000
01001 int ast_app_group_split_group(char *data, char *group, int group_max, char *category, int category_max)
01002 {
01003 int res=0;
01004 char tmp[256];
01005 char *grp=NULL, *cat=NULL;
01006
01007 if (!ast_strlen_zero(data)) {
01008 ast_copy_string(tmp, data, sizeof(tmp));
01009 grp = tmp;
01010 cat = strchr(tmp, '@');
01011 if (cat) {
01012 *cat = '\0';
01013 cat++;
01014 }
01015 }
01016
01017 if (!ast_strlen_zero(grp))
01018 ast_copy_string(group, grp, group_max);
01019 else
01020 res = -1;
01021
01022 if (cat)
01023 snprintf(category, category_max, "%s_%s", GROUP_CATEGORY_PREFIX, cat);
01024 else
01025 ast_copy_string(category, GROUP_CATEGORY_PREFIX, category_max);
01026
01027 return res;
01028 }
01029
01030 int ast_app_group_set_channel(struct ast_channel *chan, char *data)
01031 {
01032 int res=0;
01033 char group[80] = "";
01034 char category[80] = "";
01035
01036 if (!ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
01037 pbx_builtin_setvar_helper(chan, category, group);
01038 } else
01039 res = -1;
01040
01041 return res;
01042 }
01043
01044 int ast_app_group_get_count(char *group, char *category)
01045 {
01046 struct ast_channel *chan;
01047 int count = 0;
01048 char *test;
01049 char cat[80];
01050 char *s;
01051
01052 if (ast_strlen_zero(group))
01053 return 0;
01054
01055 s = (!ast_strlen_zero(category)) ? category : GROUP_CATEGORY_PREFIX;
01056 ast_copy_string(cat, s, sizeof(cat));
01057
01058 chan = NULL;
01059 while ((chan = ast_channel_walk_locked(chan)) != NULL) {
01060 test = pbx_builtin_getvar_helper(chan, cat);
01061 if (test && !strcasecmp(test, group))
01062 count++;
01063 ast_mutex_unlock(&chan->lock);
01064 }
01065
01066 return count;
01067 }
01068
01069 int ast_app_group_match_get_count(char *groupmatch, char *category)
01070 {
01071 regex_t regexbuf;
01072 struct ast_channel *chan;
01073 int count = 0;
01074 char *test;
01075 char cat[80];
01076 char *s;
01077
01078 if (ast_strlen_zero(groupmatch))
01079 return 0;
01080
01081
01082 if (regcomp(®exbuf, groupmatch, REG_EXTENDED | REG_NOSUB))
01083 return 0;
01084
01085 s = (!ast_strlen_zero(category)) ? category : GROUP_CATEGORY_PREFIX;
01086 ast_copy_string(cat, s, sizeof(cat));
01087
01088 chan = NULL;
01089 while ((chan = ast_channel_walk_locked(chan)) != NULL) {
01090 test = pbx_builtin_getvar_helper(chan, cat);
01091 if (test && !regexec(®exbuf, test, 0, NULL, 0))
01092 count++;
01093 ast_mutex_unlock(&chan->lock);
01094 }
01095
01096 regfree(®exbuf);
01097
01098 return count;
01099 }
01100
01101 unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
01102 {
01103 int argc;
01104 char *scan;
01105 int paren = 0;
01106
01107 if (!buf || !array || !arraylen)
01108 return 0;
01109
01110 memset(array, 0, arraylen * sizeof(*array));
01111
01112 scan = buf;
01113
01114 for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
01115 array[argc] = scan;
01116 for (; *scan; scan++) {
01117 if (*scan == '(')
01118 paren++;
01119 else if (*scan == ')') {
01120 if (paren)
01121 paren--;
01122 } else if ((*scan == delim) && !paren) {
01123 *scan++ = '\0';
01124 break;
01125 }
01126 }
01127 }
01128
01129 if (*scan)
01130 array[argc++] = scan;
01131
01132 return argc;
01133 }
01134
01135 enum AST_LOCK_RESULT ast_lock_path(const char *path)
01136 {
01137 char *s;
01138 char *fs;
01139 int res;
01140 int fd;
01141 time_t start;
01142
01143 s = alloca(strlen(path) + 10);
01144 fs = alloca(strlen(path) + 20);
01145
01146 if (!fs || !s) {
01147 ast_log(LOG_WARNING, "Out of memory!\n");
01148 return AST_LOCK_FAILURE;
01149 }
01150
01151 snprintf(fs, strlen(path) + 19, "%s/.lock-%08x", path, rand());
01152 fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, 0600);
01153 if (fd < 0) {
01154 fprintf(stderr, "Unable to create lock file '%s': %s\n", path, strerror(errno));
01155 return AST_LOCK_PATH_NOT_FOUND;
01156 }
01157 close(fd);
01158
01159 snprintf(s, strlen(path) + 9, "%s/.lock", path);
01160 time(&start);
01161 while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5))
01162 usleep(1);
01163 if (res) {
01164 ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
01165 return AST_LOCK_TIMEOUT;
01166 } else {
01167 unlink(fs);
01168 ast_log(LOG_DEBUG, "Locked path '%s'\n", path);
01169 return AST_LOCK_SUCCESS;
01170 }
01171 }
01172
01173 int ast_unlock_path(const char *path)
01174 {
01175 char *s;
01176 s = alloca(strlen(path) + 10);
01177 if (!s)
01178 return -1;
01179 snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01180 ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01181 return unlink(s);
01182 }
01183
01184 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
01185 {
01186 int silencethreshold = 128;
01187 int maxsilence=0;
01188 int res = 0;
01189 int cmd = 0;
01190 int max_attempts = 3;
01191 int attempts = 0;
01192 int recorded = 0;
01193 int message_exists = 0;
01194
01195
01196
01197 if (duration == NULL) {
01198 ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
01199 return -1;
01200 }
01201
01202 cmd = '3';
01203
01204 while ((cmd >= 0) && (cmd != 't')) {
01205 switch (cmd) {
01206 case '1':
01207 if (!message_exists) {
01208
01209 cmd = '3';
01210 break;
01211 } else {
01212 ast_streamfile(chan, "vm-msgsaved", chan->language);
01213 ast_waitstream(chan, "");
01214 cmd = 't';
01215 return res;
01216 }
01217 case '2':
01218
01219 ast_verbose(VERBOSE_PREFIX_3 "Reviewing the recording\n");
01220 ast_streamfile(chan, recordfile, chan->language);
01221 cmd = ast_waitstream(chan, AST_DIGIT_ANY);
01222 break;
01223 case '3':
01224 message_exists = 0;
01225
01226 if (recorded == 1)
01227 ast_verbose(VERBOSE_PREFIX_3 "Re-recording\n");
01228 else
01229 ast_verbose(VERBOSE_PREFIX_3 "Recording\n");
01230 recorded = 1;
01231 cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, silencethreshold, maxsilence, path);
01232 if (cmd == -1) {
01233
01234 return cmd;
01235 }
01236 if (cmd == '0') {
01237 break;
01238 } else if (cmd == '*') {
01239 break;
01240 }
01241 else {
01242
01243 message_exists = 1;
01244 cmd = 0;
01245 }
01246 break;
01247 case '4':
01248 case '5':
01249 case '6':
01250 case '7':
01251 case '8':
01252 case '9':
01253 case '*':
01254 case '#':
01255 cmd = ast_play_and_wait(chan, "vm-sorry");
01256 break;
01257 default:
01258 if (message_exists) {
01259 cmd = ast_play_and_wait(chan, "vm-review");
01260 }
01261 else {
01262 cmd = ast_play_and_wait(chan, "vm-torerecord");
01263 if (!cmd)
01264 cmd = ast_waitfordigit(chan, 600);
01265 }
01266
01267 if (!cmd)
01268 cmd = ast_waitfordigit(chan, 6000);
01269 if (!cmd) {
01270 attempts++;
01271 }
01272 if (attempts > max_attempts) {
01273 cmd = 't';
01274 }
01275 }
01276 }
01277 if (cmd == 't')
01278 cmd = 0;
01279 return cmd;
01280 }
01281
01282 #define RES_UPONE (1 << 16)
01283 #define RES_EXIT (1 << 17)
01284 #define RES_REPEAT (1 << 18)
01285 #define RES_RESTART ((1 << 19) | RES_REPEAT)
01286
01287 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
01288 static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
01289 {
01290 int res;
01291 int (*ivr_func)(struct ast_channel *, void *);
01292 char *c;
01293 char *n;
01294
01295 switch(option->action) {
01296 case AST_ACTION_UPONE:
01297 return RES_UPONE;
01298 case AST_ACTION_EXIT:
01299 return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
01300 case AST_ACTION_REPEAT:
01301 return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
01302 case AST_ACTION_RESTART:
01303 return RES_RESTART ;
01304 case AST_ACTION_NOOP:
01305 return 0;
01306 case AST_ACTION_BACKGROUND:
01307 res = ast_streamfile(chan, (char *)option->adata, chan->language);
01308 if (!res) {
01309 res = ast_waitstream(chan, AST_DIGIT_ANY);
01310 } else {
01311 ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01312 res = 0;
01313 }
01314 return res;
01315 case AST_ACTION_PLAYBACK:
01316 res = ast_streamfile(chan, (char *)option->adata, chan->language);
01317 if (!res) {
01318 res = ast_waitstream(chan, "");
01319 } else {
01320 ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01321 res = 0;
01322 }
01323 return res;
01324 case AST_ACTION_MENU:
01325 res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata);
01326
01327 if (res == -2)
01328 res = 0;
01329 return res;
01330 case AST_ACTION_WAITOPTION:
01331 res = ast_waitfordigit(chan, 1000 * (chan->pbx ? chan->pbx->rtimeout : 10));
01332 if (!res)
01333 return 't';
01334 return res;
01335 case AST_ACTION_CALLBACK:
01336 ivr_func = option->adata;
01337 res = ivr_func(chan, cbdata);
01338 return res;
01339 case AST_ACTION_TRANSFER:
01340 res = ast_parseable_goto(chan, option->adata);
01341 return 0;
01342 case AST_ACTION_PLAYLIST:
01343 case AST_ACTION_BACKLIST:
01344 res = 0;
01345 c = ast_strdupa(option->adata);
01346 if (c) {
01347 while((n = strsep(&c, ";")))
01348 if ((res = ast_streamfile(chan, n, chan->language)) || (res = ast_waitstream(chan, (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : "")))
01349 break;
01350 ast_stopstream(chan);
01351 }
01352 return res;
01353 default:
01354 ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
01355 return 0;
01356 };
01357 return -1;
01358 }
01359
01360 static int option_exists(struct ast_ivr_menu *menu, char *option)
01361 {
01362 int x;
01363 for (x=0;menu->options[x].option;x++)
01364 if (!strcasecmp(menu->options[x].option, option))
01365 return x;
01366 return -1;
01367 }
01368
01369 static int option_matchmore(struct ast_ivr_menu *menu, char *option)
01370 {
01371 int x;
01372 for (x=0;menu->options[x].option;x++)
01373 if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
01374 (menu->options[x].option[strlen(option)]))
01375 return x;
01376 return -1;
01377 }
01378
01379 static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
01380 {
01381 int res=0;
01382 int ms;
01383 while(option_matchmore(menu, exten)) {
01384 ms = chan->pbx ? chan->pbx->dtimeout : 5000;
01385 if (strlen(exten) >= maxexten - 1)
01386 break;
01387 res = ast_waitfordigit(chan, ms);
01388 if (res < 1)
01389 break;
01390 exten[strlen(exten) + 1] = '\0';
01391 exten[strlen(exten)] = res;
01392 }
01393 return res > 0 ? 0 : res;
01394 }
01395
01396 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01397 {
01398
01399 int res=0;
01400 int pos = 0;
01401 int retries = 0;
01402 char exten[AST_MAX_EXTENSION] = "s";
01403 if (option_exists(menu, "s") < 0) {
01404 strcpy(exten, "g");
01405 if (option_exists(menu, "g") < 0) {
01406 ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
01407 return -1;
01408 }
01409 }
01410 while(!res) {
01411 while(menu->options[pos].option) {
01412 if (!strcasecmp(menu->options[pos].option, exten)) {
01413 res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
01414 ast_log(LOG_DEBUG, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
01415 if (res < 0)
01416 break;
01417 else if (res & RES_UPONE)
01418 return 0;
01419 else if (res & RES_EXIT)
01420 return res;
01421 else if (res & RES_REPEAT) {
01422 int maxretries = res & 0xffff;
01423 if ((res & RES_RESTART) == RES_RESTART) {
01424 retries = 0;
01425 } else
01426 retries++;
01427 if (!maxretries)
01428 maxretries = 3;
01429 if ((maxretries > 0) && (retries >= maxretries)) {
01430 ast_log(LOG_DEBUG, "Max retries %d exceeded\n", maxretries);
01431 return -2;
01432 } else {
01433 if (option_exists(menu, "g") > -1)
01434 strcpy(exten, "g");
01435 else if (option_exists(menu, "s") > -1)
01436 strcpy(exten, "s");
01437 }
01438 pos=0;
01439 continue;
01440 } else if (res && strchr(AST_DIGIT_ANY, res)) {
01441 ast_log(LOG_DEBUG, "Got start of extension, %c\n", res);
01442 exten[1] = '\0';
01443 exten[0] = res;
01444 if ((res = read_newoption(chan, menu, exten, sizeof(exten))))
01445 break;
01446 if (option_exists(menu, exten) < 0) {
01447 if (option_exists(menu, "i")) {
01448 ast_log(LOG_DEBUG, "Invalid extension entered, going to 'i'!\n");
01449 strcpy(exten, "i");
01450 pos = 0;
01451 continue;
01452 } else {
01453 ast_log(LOG_DEBUG, "Aborting on invalid entry, with no 'i' option!\n");
01454 res = -2;
01455 break;
01456 }
01457 } else {
01458 ast_log(LOG_DEBUG, "New existing extension: %s\n", exten);
01459 pos = 0;
01460 continue;
01461 }
01462 }
01463 }
01464 pos++;
01465 }
01466 ast_log(LOG_DEBUG, "Stopping option '%s', res is %d\n", exten, res);
01467 pos = 0;
01468 if (!strcasecmp(exten, "s"))
01469 strcpy(exten, "g");
01470 else
01471 break;
01472 }
01473 return res;
01474 }
01475
01476 int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01477 {
01478 int res;
01479 res = ast_ivr_menu_run_internal(chan, menu, cbdata);
01480
01481 if (res > 0)
01482 res = 0;
01483 return res;
01484 }
01485
01486 char *ast_read_textfile(const char *filename)
01487 {
01488 int fd;
01489 char *output=NULL;
01490 struct stat filesize;
01491 int count=0;
01492 int res;
01493 if(stat(filename,&filesize)== -1){
01494 ast_log(LOG_WARNING,"Error can't stat %s\n", filename);
01495 return NULL;
01496 }
01497 count=filesize.st_size + 1;
01498 fd = open(filename, O_RDONLY);
01499 if (fd < 0) {
01500 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
01501 return NULL;
01502 }
01503 output=(char *)malloc(count);
01504 if (output) {
01505 res = read(fd, output, count - 1);
01506 if (res == count - 1) {
01507 output[res] = '\0';
01508 } else {
01509 ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
01510 free(output);
01511 output = NULL;
01512 }
01513 } else
01514 ast_log(LOG_WARNING, "Out of memory!\n");
01515 close(fd);
01516 return output;
01517 }
01518
01519 int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
01520 {
01521 char *s;
01522 int curarg;
01523 unsigned int argloc;
01524 char *arg;
01525 int res = 0;
01526
01527 ast_clear_flag(flags, AST_FLAGS_ALL);
01528
01529 if (!optstr)
01530 return 0;
01531
01532 s = optstr;
01533 while (*s) {
01534 curarg = *s++ & 0x7f;
01535 ast_set_flag(flags, options[curarg].flag);
01536 argloc = options[curarg].arg_index;
01537 if (*s == '(') {
01538
01539 arg = ++s;
01540 while (*s && (*s != ')'))
01541 s++;
01542 if (*s) {
01543 if (argloc)
01544 args[argloc - 1] = arg;
01545 *s++ = '\0';
01546 } else {
01547 ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
01548 res = -1;
01549 }
01550 } else if (argloc) {
01551 args[argloc - 1] = NULL;
01552 }
01553 }
01554
01555 return res;
01556 }