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