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