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