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