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