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