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: 337118 $")
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
00738 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)
00739 {
00740 int d = 0;
00741 char *fmts;
00742 char comment[256];
00743 int x, fmtcnt = 1, res = -1, outmsg = 0;
00744 struct ast_filestream *others[AST_MAX_FORMATS];
00745 char *sfmt[AST_MAX_FORMATS];
00746 char *stringp = NULL;
00747 time_t start, end;
00748 struct ast_dsp *sildet = NULL;
00749 int totalsilence = 0;
00750 int dspsilence = 0;
00751 int olddspsilence = 0;
00752 int rfmt = 0;
00753 struct ast_silence_generator *silgen = NULL;
00754 char prependfile[80];
00755
00756 if (silencethreshold < 0) {
00757 silencethreshold = global_silence_threshold;
00758 }
00759
00760 if (maxsilence < 0) {
00761 maxsilence = global_maxsilence;
00762 }
00763
00764
00765 if (!duration) {
00766 ast_log(LOG_WARNING, "Error play_and_record called without duration pointer\n");
00767 return -1;
00768 }
00769
00770 ast_debug(1, "play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
00771 snprintf(comment, sizeof(comment), "Playing %s, Recording to: %s on %s\n", playfile ? playfile : "<None>", recordfile, chan->name);
00772
00773 if (playfile || beep) {
00774 if (!beep) {
00775 d = ast_play_and_wait(chan, playfile);
00776 }
00777 if (d > -1) {
00778 d = ast_stream_and_wait(chan, "beep", "");
00779 }
00780 if (d < 0) {
00781 return -1;
00782 }
00783 }
00784
00785 if (prepend) {
00786 ast_copy_string(prependfile, recordfile, sizeof(prependfile));
00787 strncat(prependfile, "-prepend", sizeof(prependfile) - strlen(prependfile) - 1);
00788 }
00789
00790 fmts = ast_strdupa(fmt);
00791
00792 stringp = fmts;
00793 strsep(&stringp, "|");
00794 ast_debug(1, "Recording Formats: sfmts=%s\n", fmts);
00795 sfmt[0] = ast_strdupa(fmts);
00796
00797 while ((fmt = strsep(&stringp, "|"))) {
00798 if (fmtcnt > AST_MAX_FORMATS - 1) {
00799 ast_log(LOG_WARNING, "Please increase AST_MAX_FORMATS in file.h\n");
00800 break;
00801 }
00802 sfmt[fmtcnt++] = ast_strdupa(fmt);
00803 }
00804
00805 end = start = time(NULL);
00806 for (x = 0; x < fmtcnt; x++) {
00807 others[x] = ast_writefile(prepend ? prependfile : recordfile, sfmt[x], comment, O_TRUNC, 0, AST_FILE_MODE);
00808 ast_verb(3, "x=%d, open writing: %s format: %s, %p\n", x, prepend ? prependfile : recordfile, sfmt[x], others[x]);
00809
00810 if (!others[x]) {
00811 break;
00812 }
00813 }
00814
00815 if (path) {
00816 ast_unlock_path(path);
00817 }
00818
00819 if (maxsilence > 0) {
00820 sildet = ast_dsp_new();
00821 if (!sildet) {
00822 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
00823 return -1;
00824 }
00825 ast_dsp_set_threshold(sildet, silencethreshold);
00826 rfmt = chan->readformat;
00827 res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
00828 if (res < 0) {
00829 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
00830 ast_dsp_free(sildet);
00831 return -1;
00832 }
00833 }
00834
00835 if (!prepend) {
00836
00837 ast_indicate(chan, AST_CONTROL_VIDUPDATE);
00838
00839 if (ast_opt_transmit_silence) {
00840 silgen = ast_channel_start_silence_generator(chan);
00841 }
00842 }
00843
00844 if (x == fmtcnt) {
00845
00846
00847 struct ast_frame *f;
00848 for (;;) {
00849 if (!(res = ast_waitfor(chan, 2000))) {
00850 ast_debug(1, "One waitfor failed, trying another\n");
00851
00852 if (!(res = ast_waitfor(chan, 2000))) {
00853 ast_log(LOG_WARNING, "No audio available on %s??\n", chan->name);
00854 res = -1;
00855 }
00856 }
00857
00858 if (res < 0) {
00859 f = NULL;
00860 break;
00861 }
00862 if (!(f = ast_read(chan))) {
00863 break;
00864 }
00865 if (f->frametype == AST_FRAME_VOICE) {
00866
00867 for (x = 0; x < fmtcnt; x++) {
00868 if (prepend && !others[x]) {
00869 break;
00870 }
00871 res = ast_writestream(others[x], f);
00872 }
00873
00874
00875 if (maxsilence > 0) {
00876 dspsilence = 0;
00877 ast_dsp_silence(sildet, f, &dspsilence);
00878 if (olddspsilence > dspsilence) {
00879 totalsilence += olddspsilence;
00880 }
00881 olddspsilence = dspsilence;
00882
00883 if (dspsilence > maxsilence) {
00884
00885 ast_verb(3, "Recording automatically stopped after a silence of %d seconds\n", dspsilence/1000);
00886 res = 'S';
00887 outmsg = 2;
00888 break;
00889 }
00890 }
00891
00892 if (res) {
00893 ast_log(LOG_WARNING, "Error writing frame\n");
00894 break;
00895 }
00896 } else if (f->frametype == AST_FRAME_VIDEO) {
00897
00898 ast_writestream(others[0], f);
00899 } else if (f->frametype == AST_FRAME_DTMF) {
00900 if (prepend) {
00901
00902 ast_verb(3, "User ended message by pressing %c\n", f->subclass.integer);
00903 res = 't';
00904 outmsg = 2;
00905 break;
00906 }
00907 if (strchr(acceptdtmf, f->subclass.integer)) {
00908 ast_verb(3, "User ended message by pressing %c\n", f->subclass.integer);
00909 res = f->subclass.integer;
00910 outmsg = 2;
00911 break;
00912 }
00913 if (strchr(canceldtmf, f->subclass.integer)) {
00914 ast_verb(3, "User cancelled message by pressing %c\n", f->subclass.integer);
00915 res = f->subclass.integer;
00916 outmsg = 0;
00917 break;
00918 }
00919 }
00920 if (maxtime) {
00921 end = time(NULL);
00922 if (maxtime < (end - start)) {
00923 ast_verb(3, "Took too long, cutting it short...\n");
00924 res = 't';
00925 outmsg = 2;
00926 break;
00927 }
00928 }
00929 ast_frfree(f);
00930 }
00931 if (!f) {
00932 ast_verb(3, "User hung up\n");
00933 res = -1;
00934 outmsg = 1;
00935 } else {
00936 ast_frfree(f);
00937 }
00938 } else {
00939 ast_log(LOG_WARNING, "Error creating writestream '%s', format '%s'\n", recordfile, sfmt[x]);
00940 }
00941
00942 if (!prepend) {
00943 if (silgen) {
00944 ast_channel_stop_silence_generator(chan, silgen);
00945 }
00946 }
00947
00948
00949
00950
00951
00952
00953
00954
00955
00956
00957 *duration = others[0] ? ast_tellstream(others[0]) / 8000 : 0;
00958 if (sound_duration) {
00959 *sound_duration = *duration;
00960 }
00961
00962 if (!prepend) {
00963
00964 if (olddspsilence <= dspsilence) {
00965 totalsilence += dspsilence;
00966 }
00967
00968 if (sound_duration) {
00969 if (totalsilence > 0) {
00970 *sound_duration -= (totalsilence - 200) / 1000;
00971 }
00972 if (*sound_duration < 0) {
00973 *sound_duration = 0;
00974 }
00975 }
00976
00977 if (dspsilence > 0) {
00978 *duration -= (dspsilence - 200) / 1000;
00979 }
00980 if (*duration < 0) {
00981 *duration = 0;
00982 }
00983
00984 for (x = 0; x < fmtcnt; x++) {
00985 if (!others[x]) {
00986 break;
00987 }
00988
00989
00990
00991
00992
00993 if (res > 0 && dspsilence) {
00994
00995 ast_stream_rewind(others[x], dspsilence - 200);
00996 }
00997 ast_truncstream(others[x]);
00998 ast_closestream(others[x]);
00999 }
01000 }
01001
01002 if (prepend && outmsg) {
01003 struct ast_filestream *realfiles[AST_MAX_FORMATS];
01004 struct ast_frame *fr;
01005
01006 for (x = 0; x < fmtcnt; x++) {
01007 snprintf(comment, sizeof(comment), "Opening the real file %s.%s\n", recordfile, sfmt[x]);
01008 realfiles[x] = ast_readfile(recordfile, sfmt[x], comment, O_RDONLY, 0, 0);
01009 if (!others[x] || !realfiles[x]) {
01010 break;
01011 }
01012
01013 if (dspsilence) {
01014 ast_stream_rewind(others[x], dspsilence - 200);
01015 }
01016 ast_truncstream(others[x]);
01017
01018 while ((fr = ast_readframe(realfiles[x]))) {
01019 ast_writestream(others[x], fr);
01020 ast_frfree(fr);
01021 }
01022 ast_closestream(others[x]);
01023 ast_closestream(realfiles[x]);
01024 ast_filerename(prependfile, recordfile, sfmt[x]);
01025 ast_verb(4, "Recording Format: sfmts=%s, prependfile %s, recordfile %s\n", sfmt[x], prependfile, recordfile);
01026 ast_filedelete(prependfile, sfmt[x]);
01027 }
01028 }
01029 if (rfmt && ast_set_read_format(chan, rfmt)) {
01030 ast_log(LOG_WARNING, "Unable to restore format %s to channel '%s'\n", ast_getformatname(rfmt), chan->name);
01031 }
01032 if ((outmsg == 2) && (!skip_confirmation_sound)) {
01033 ast_stream_and_wait(chan, "auth-thankyou", "");
01034 }
01035 if (sildet) {
01036 ast_dsp_free(sildet);
01037 }
01038 return res;
01039 }
01040
01041 static const char default_acceptdtmf[] = "#";
01042 static const char default_canceldtmf[] = "";
01043
01044 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)
01045 {
01046 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);
01047 }
01048
01049 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)
01050 {
01051 return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, 0, silencethreshold, maxsilence, path, 0, default_acceptdtmf, default_canceldtmf, 0);
01052 }
01053
01054 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)
01055 {
01056 return __ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, sound_duration, beep, silencethreshold, maxsilence, NULL, 1, default_acceptdtmf, default_canceldtmf, 1);
01057 }
01058
01059
01060
01061 int ast_app_group_split_group(const char *data, char *group, int group_max, char *category, int category_max)
01062 {
01063 int res = 0;
01064 char tmp[256];
01065 char *grp = NULL, *cat = NULL;
01066
01067 if (!ast_strlen_zero(data)) {
01068 ast_copy_string(tmp, data, sizeof(tmp));
01069 grp = tmp;
01070 if ((cat = strchr(tmp, '@'))) {
01071 *cat++ = '\0';
01072 }
01073 }
01074
01075 if (!ast_strlen_zero(grp)) {
01076 ast_copy_string(group, grp, group_max);
01077 } else {
01078 *group = '\0';
01079 }
01080
01081 if (!ast_strlen_zero(cat)) {
01082 ast_copy_string(category, cat, category_max);
01083 }
01084
01085 return res;
01086 }
01087
01088 int ast_app_group_set_channel(struct ast_channel *chan, const char *data)
01089 {
01090 int res = 0;
01091 char group[80] = "", category[80] = "";
01092 struct ast_group_info *gi = NULL;
01093 size_t len = 0;
01094
01095 if (ast_app_group_split_group(data, group, sizeof(group), category, sizeof(category))) {
01096 return -1;
01097 }
01098
01099
01100 len = sizeof(*gi) + strlen(group) + 1;
01101 if (!ast_strlen_zero(category)) {
01102 len += strlen(category) + 1;
01103 }
01104
01105 AST_RWLIST_WRLOCK(&groups);
01106 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01107 if ((gi->chan == chan) && ((ast_strlen_zero(category) && ast_strlen_zero(gi->category)) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01108 AST_RWLIST_REMOVE_CURRENT(group_list);
01109 free(gi);
01110 break;
01111 }
01112 }
01113 AST_RWLIST_TRAVERSE_SAFE_END;
01114
01115 if (ast_strlen_zero(group)) {
01116
01117 } else if ((gi = calloc(1, len))) {
01118 gi->chan = chan;
01119 gi->group = (char *) gi + sizeof(*gi);
01120 strcpy(gi->group, group);
01121 if (!ast_strlen_zero(category)) {
01122 gi->category = (char *) gi + sizeof(*gi) + strlen(group) + 1;
01123 strcpy(gi->category, category);
01124 }
01125 AST_RWLIST_INSERT_TAIL(&groups, gi, group_list);
01126 } else {
01127 res = -1;
01128 }
01129
01130 AST_RWLIST_UNLOCK(&groups);
01131
01132 return res;
01133 }
01134
01135 int ast_app_group_get_count(const char *group, const char *category)
01136 {
01137 struct ast_group_info *gi = NULL;
01138 int count = 0;
01139
01140 if (ast_strlen_zero(group)) {
01141 return 0;
01142 }
01143
01144 AST_RWLIST_RDLOCK(&groups);
01145 AST_RWLIST_TRAVERSE(&groups, gi, group_list) {
01146 if (!strcasecmp(gi->group, group) && (ast_strlen_zero(category) || (!ast_strlen_zero(gi->category) && !strcasecmp(gi->category, category)))) {
01147 count++;
01148 }
01149 }
01150 AST_RWLIST_UNLOCK(&groups);
01151
01152 return count;
01153 }
01154
01155 int ast_app_group_match_get_count(const char *groupmatch, const char *category)
01156 {
01157 struct ast_group_info *gi = NULL;
01158 regex_t regexbuf_group;
01159 regex_t regexbuf_category;
01160 int count = 0;
01161
01162 if (ast_strlen_zero(groupmatch)) {
01163 ast_log(LOG_NOTICE, "groupmatch empty\n");
01164 return 0;
01165 }
01166
01167
01168 if (regcomp(®exbuf_group, groupmatch, REG_EXTENDED | REG_NOSUB)) {
01169 ast_log(LOG_ERROR, "Regex compile failed on: %s\n", groupmatch);
01170 return 0;
01171 }
01172
01173 if (!ast_strlen_zero(category) && regcomp(®exbuf_category, category, REG_EXTENDED | REG_NOSUB)) {
01174 ast_log(LOG_ERROR, "Regex compile failed on: %s\n", category);
01175 return 0;
01176 }
01177
01178 AST_RWLIST_RDLOCK(&groups);
01179 AST_RWLIST_TRAVERSE(&groups, gi, group_list) {
01180 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)))) {
01181 count++;
01182 }
01183 }
01184 AST_RWLIST_UNLOCK(&groups);
01185
01186 regfree(®exbuf_group);
01187 if (!ast_strlen_zero(category)) {
01188 regfree(®exbuf_category);
01189 }
01190
01191 return count;
01192 }
01193
01194 int ast_app_group_update(struct ast_channel *old, struct ast_channel *new)
01195 {
01196 struct ast_group_info *gi = NULL;
01197
01198 AST_RWLIST_WRLOCK(&groups);
01199 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01200 if (gi->chan == old) {
01201 gi->chan = new;
01202 } else if (gi->chan == new) {
01203 AST_RWLIST_REMOVE_CURRENT(group_list);
01204 ast_free(gi);
01205 }
01206 }
01207 AST_RWLIST_TRAVERSE_SAFE_END;
01208 AST_RWLIST_UNLOCK(&groups);
01209
01210 return 0;
01211 }
01212
01213 int ast_app_group_discard(struct ast_channel *chan)
01214 {
01215 struct ast_group_info *gi = NULL;
01216
01217 AST_RWLIST_WRLOCK(&groups);
01218 AST_RWLIST_TRAVERSE_SAFE_BEGIN(&groups, gi, group_list) {
01219 if (gi->chan == chan) {
01220 AST_RWLIST_REMOVE_CURRENT(group_list);
01221 ast_free(gi);
01222 }
01223 }
01224 AST_RWLIST_TRAVERSE_SAFE_END;
01225 AST_RWLIST_UNLOCK(&groups);
01226
01227 return 0;
01228 }
01229
01230 int ast_app_group_list_wrlock(void)
01231 {
01232 return AST_RWLIST_WRLOCK(&groups);
01233 }
01234
01235 int ast_app_group_list_rdlock(void)
01236 {
01237 return AST_RWLIST_RDLOCK(&groups);
01238 }
01239
01240 struct ast_group_info *ast_app_group_list_head(void)
01241 {
01242 return AST_RWLIST_FIRST(&groups);
01243 }
01244
01245 int ast_app_group_list_unlock(void)
01246 {
01247 return AST_RWLIST_UNLOCK(&groups);
01248 }
01249
01250 #undef ast_app_separate_args
01251 unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen);
01252
01253 unsigned int __ast_app_separate_args(char *buf, char delim, int remove_chars, char **array, int arraylen)
01254 {
01255 int argc;
01256 char *scan, *wasdelim = NULL;
01257 int paren = 0, quote = 0, bracket = 0;
01258
01259 if (!array || !arraylen) {
01260 return 0;
01261 }
01262
01263 memset(array, 0, arraylen * sizeof(*array));
01264
01265 if (!buf) {
01266 return 0;
01267 }
01268
01269 scan = buf;
01270
01271 for (argc = 0; *scan && (argc < arraylen - 1); argc++) {
01272 array[argc] = scan;
01273 for (; *scan; scan++) {
01274 if (*scan == '(') {
01275 paren++;
01276 } else if (*scan == ')') {
01277 if (paren) {
01278 paren--;
01279 }
01280 } else if (*scan == '[') {
01281 bracket++;
01282 } else if (*scan == ']') {
01283 if (bracket) {
01284 bracket--;
01285 }
01286 } else if (*scan == '"' && delim != '"') {
01287 quote = quote ? 0 : 1;
01288 if (remove_chars) {
01289
01290 memmove(scan, scan + 1, strlen(scan));
01291 scan--;
01292 }
01293 } else if (*scan == '\\') {
01294 if (remove_chars) {
01295
01296 memmove(scan, scan + 1, strlen(scan));
01297 } else {
01298 scan++;
01299 }
01300 } else if ((*scan == delim) && !paren && !quote && !bracket) {
01301 wasdelim = scan;
01302 *scan++ = '\0';
01303 break;
01304 }
01305 }
01306 }
01307
01308
01309
01310 if (*scan || (scan > buf && (scan - 1) == wasdelim)) {
01311 array[argc++] = scan;
01312 }
01313
01314 return argc;
01315 }
01316
01317
01318 unsigned int ast_app_separate_args(char *buf, char delim, char **array, int arraylen)
01319 {
01320 return __ast_app_separate_args(buf, delim, 1, array, arraylen);
01321 }
01322
01323 static enum AST_LOCK_RESULT ast_lock_path_lockfile(const char *path)
01324 {
01325 char *s;
01326 char *fs;
01327 int res;
01328 int fd;
01329 int lp = strlen(path);
01330 time_t start;
01331
01332 s = alloca(lp + 10);
01333 fs = alloca(lp + 20);
01334
01335 snprintf(fs, strlen(path) + 19, "%s/.lock-%08lx", path, ast_random());
01336 fd = open(fs, O_WRONLY | O_CREAT | O_EXCL, AST_FILE_MODE);
01337 if (fd < 0) {
01338 ast_log(LOG_ERROR, "Unable to create lock file '%s': %s\n", path, strerror(errno));
01339 return AST_LOCK_PATH_NOT_FOUND;
01340 }
01341 close(fd);
01342
01343 snprintf(s, strlen(path) + 9, "%s/.lock", path);
01344 start = time(NULL);
01345 while (((res = link(fs, s)) < 0) && (errno == EEXIST) && (time(NULL) - start < 5)) {
01346 sched_yield();
01347 }
01348
01349 unlink(fs);
01350
01351 if (res) {
01352 ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n", path, strerror(errno));
01353 return AST_LOCK_TIMEOUT;
01354 } else {
01355 ast_debug(1, "Locked path '%s'\n", path);
01356 return AST_LOCK_SUCCESS;
01357 }
01358 }
01359
01360 static int ast_unlock_path_lockfile(const char *path)
01361 {
01362 char *s;
01363 int res;
01364
01365 s = alloca(strlen(path) + 10);
01366
01367 snprintf(s, strlen(path) + 9, "%s/%s", path, ".lock");
01368
01369 if ((res = unlink(s))) {
01370 ast_log(LOG_ERROR, "Could not unlock path '%s': %s\n", path, strerror(errno));
01371 } else {
01372 ast_debug(1, "Unlocked path '%s'\n", path);
01373 }
01374
01375 return res;
01376 }
01377
01378 struct path_lock {
01379 AST_LIST_ENTRY(path_lock) le;
01380 int fd;
01381 char *path;
01382 };
01383
01384 static AST_LIST_HEAD_STATIC(path_lock_list, path_lock);
01385
01386 static void path_lock_destroy(struct path_lock *obj)
01387 {
01388 if (obj->fd >= 0) {
01389 close(obj->fd);
01390 }
01391 if (obj->path) {
01392 free(obj->path);
01393 }
01394 free(obj);
01395 }
01396
01397 static enum AST_LOCK_RESULT ast_lock_path_flock(const char *path)
01398 {
01399 char *fs;
01400 int res;
01401 int fd;
01402 time_t start;
01403 struct path_lock *pl;
01404 struct stat st, ost;
01405
01406 fs = alloca(strlen(path) + 20);
01407
01408 snprintf(fs, strlen(path) + 19, "%s/lock", path);
01409 if (lstat(fs, &st) == 0) {
01410 if ((st.st_mode & S_IFMT) == S_IFLNK) {
01411 ast_log(LOG_WARNING, "Unable to create lock file "
01412 "'%s': it's already a symbolic link\n",
01413 fs);
01414 return AST_LOCK_FAILURE;
01415 }
01416 if (st.st_nlink > 1) {
01417 ast_log(LOG_WARNING, "Unable to create lock file "
01418 "'%s': %u hard links exist\n",
01419 fs, (unsigned int) st.st_nlink);
01420 return AST_LOCK_FAILURE;
01421 }
01422 }
01423 if ((fd = open(fs, O_WRONLY | O_CREAT, 0600)) < 0) {
01424 ast_log(LOG_WARNING, "Unable to create lock file '%s': %s\n",
01425 fs, strerror(errno));
01426 return AST_LOCK_PATH_NOT_FOUND;
01427 }
01428 if (!(pl = ast_calloc(1, sizeof(*pl)))) {
01429
01430
01431
01432
01433
01434 close(fd);
01435 return AST_LOCK_FAILURE;
01436 }
01437 pl->fd = fd;
01438 pl->path = strdup(path);
01439
01440 time(&start);
01441 while (
01442 #ifdef SOLARIS
01443 ((res = fcntl(pl->fd, F_SETLK, fcntl(pl->fd, F_GETFL) | O_NONBLOCK)) < 0) &&
01444 #else
01445 ((res = flock(pl->fd, LOCK_EX | LOCK_NB)) < 0) &&
01446 #endif
01447 (errno == EWOULDBLOCK) &&
01448 (time(NULL) - start < 5))
01449 usleep(1000);
01450 if (res) {
01451 ast_log(LOG_WARNING, "Failed to lock path '%s': %s\n",
01452 path, strerror(errno));
01453
01454
01455
01456 path_lock_destroy(pl);
01457 return AST_LOCK_TIMEOUT;
01458 }
01459
01460
01461
01462
01463 if (lstat(fs, &st) != 0 && fstat(pl->fd, &ost) != 0 &&
01464 st.st_dev != ost.st_dev &&
01465 st.st_ino != ost.st_ino) {
01466 ast_log(LOG_WARNING, "Unable to create lock file '%s': "
01467 "file changed underneath us\n", fs);
01468 path_lock_destroy(pl);
01469 return AST_LOCK_FAILURE;
01470 }
01471
01472
01473 AST_LIST_LOCK(&path_lock_list);
01474 AST_LIST_INSERT_TAIL(&path_lock_list, pl, le);
01475 AST_LIST_UNLOCK(&path_lock_list);
01476
01477 ast_debug(1, "Locked path '%s'\n", path);
01478
01479 return AST_LOCK_SUCCESS;
01480 }
01481
01482 static int ast_unlock_path_flock(const char *path)
01483 {
01484 char *s;
01485 struct path_lock *p;
01486
01487 s = alloca(strlen(path) + 20);
01488
01489 AST_LIST_LOCK(&path_lock_list);
01490 AST_LIST_TRAVERSE_SAFE_BEGIN(&path_lock_list, p, le) {
01491 if (!strcmp(p->path, path)) {
01492 AST_LIST_REMOVE_CURRENT(le);
01493 break;
01494 }
01495 }
01496 AST_LIST_TRAVERSE_SAFE_END;
01497 AST_LIST_UNLOCK(&path_lock_list);
01498
01499 if (p) {
01500 snprintf(s, strlen(path) + 19, "%s/lock", path);
01501 unlink(s);
01502 path_lock_destroy(p);
01503 ast_log(LOG_DEBUG, "Unlocked path '%s'\n", path);
01504 } else {
01505 ast_log(LOG_DEBUG, "Failed to unlock path '%s': "
01506 "lock not found\n", path);
01507 }
01508
01509 return 0;
01510 }
01511
01512 void ast_set_lock_type(enum AST_LOCK_TYPE type)
01513 {
01514 ast_lock_type = type;
01515 }
01516
01517 enum AST_LOCK_RESULT ast_lock_path(const char *path)
01518 {
01519 enum AST_LOCK_RESULT r = AST_LOCK_FAILURE;
01520
01521 switch (ast_lock_type) {
01522 case AST_LOCK_TYPE_LOCKFILE:
01523 r = ast_lock_path_lockfile(path);
01524 break;
01525 case AST_LOCK_TYPE_FLOCK:
01526 r = ast_lock_path_flock(path);
01527 break;
01528 }
01529
01530 return r;
01531 }
01532
01533 int ast_unlock_path(const char *path)
01534 {
01535 int r = 0;
01536
01537 switch (ast_lock_type) {
01538 case AST_LOCK_TYPE_LOCKFILE:
01539 r = ast_unlock_path_lockfile(path);
01540 break;
01541 case AST_LOCK_TYPE_FLOCK:
01542 r = ast_unlock_path_flock(path);
01543 break;
01544 }
01545
01546 return r;
01547 }
01548
01549 int ast_record_review(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime, const char *fmt, int *duration, const char *path)
01550 {
01551 int silencethreshold;
01552 int maxsilence = 0;
01553 int res = 0;
01554 int cmd = 0;
01555 int max_attempts = 3;
01556 int attempts = 0;
01557 int recorded = 0;
01558 int message_exists = 0;
01559
01560
01561
01562 if (!duration) {
01563 ast_log(LOG_WARNING, "Error ast_record_review called without duration pointer\n");
01564 return -1;
01565 }
01566
01567 cmd = '3';
01568
01569 silencethreshold = ast_dsp_get_threshold_from_settings(THRESHOLD_SILENCE);
01570
01571 while ((cmd >= 0) && (cmd != 't')) {
01572 switch (cmd) {
01573 case '1':
01574 if (!message_exists) {
01575
01576 cmd = '3';
01577 break;
01578 } else {
01579 ast_stream_and_wait(chan, "vm-msgsaved", "");
01580 cmd = 't';
01581 return res;
01582 }
01583 case '2':
01584
01585 ast_verb(3, "Reviewing the recording\n");
01586 cmd = ast_stream_and_wait(chan, recordfile, AST_DIGIT_ANY);
01587 break;
01588 case '3':
01589 message_exists = 0;
01590
01591 ast_verb(3, "R%secording\n", recorded == 1 ? "e-r" : "");
01592 recorded = 1;
01593 if ((cmd = ast_play_and_record(chan, playfile, recordfile, maxtime, fmt, duration, NULL, silencethreshold, maxsilence, path)) == -1) {
01594
01595 return cmd;
01596 }
01597 if (cmd == '0') {
01598 break;
01599 } else if (cmd == '*') {
01600 break;
01601 } else {
01602
01603 message_exists = 1;
01604 cmd = 0;
01605 }
01606 break;
01607 case '4':
01608 case '5':
01609 case '6':
01610 case '7':
01611 case '8':
01612 case '9':
01613 case '*':
01614 case '#':
01615 cmd = ast_play_and_wait(chan, "vm-sorry");
01616 break;
01617 default:
01618 if (message_exists) {
01619 cmd = ast_play_and_wait(chan, "vm-review");
01620 } else {
01621 if (!(cmd = ast_play_and_wait(chan, "vm-torerecord"))) {
01622 cmd = ast_waitfordigit(chan, 600);
01623 }
01624 }
01625
01626 if (!cmd) {
01627 cmd = ast_waitfordigit(chan, 6000);
01628 }
01629 if (!cmd) {
01630 attempts++;
01631 }
01632 if (attempts > max_attempts) {
01633 cmd = 't';
01634 }
01635 }
01636 }
01637 if (cmd == 't') {
01638 cmd = 0;
01639 }
01640 return cmd;
01641 }
01642
01643 #define RES_UPONE (1 << 16)
01644 #define RES_EXIT (1 << 17)
01645 #define RES_REPEAT (1 << 18)
01646 #define RES_RESTART ((1 << 19) | RES_REPEAT)
01647
01648 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata);
01649
01650 static int ivr_dispatch(struct ast_channel *chan, struct ast_ivr_option *option, char *exten, void *cbdata)
01651 {
01652 int res;
01653 int (*ivr_func)(struct ast_channel *, void *);
01654 char *c;
01655 char *n;
01656
01657 switch (option->action) {
01658 case AST_ACTION_UPONE:
01659 return RES_UPONE;
01660 case AST_ACTION_EXIT:
01661 return RES_EXIT | (((unsigned long)(option->adata)) & 0xffff);
01662 case AST_ACTION_REPEAT:
01663 return RES_REPEAT | (((unsigned long)(option->adata)) & 0xffff);
01664 case AST_ACTION_RESTART:
01665 return RES_RESTART ;
01666 case AST_ACTION_NOOP:
01667 return 0;
01668 case AST_ACTION_BACKGROUND:
01669 res = ast_stream_and_wait(chan, (char *)option->adata, AST_DIGIT_ANY);
01670 if (res < 0) {
01671 ast_log(LOG_NOTICE, "Unable to find file '%s'!\n", (char *)option->adata);
01672 res = 0;
01673 }
01674 return res;
01675 case AST_ACTION_PLAYBACK:
01676 res = ast_stream_and_wait(chan, (char *)option->adata, "");
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_MENU:
01683 if ((res = ast_ivr_menu_run_internal(chan, (struct ast_ivr_menu *)option->adata, cbdata)) == -2) {
01684
01685 res = 0;
01686 }
01687 return res;
01688 case AST_ACTION_WAITOPTION:
01689 if (!(res = ast_waitfordigit(chan, chan->pbx ? chan->pbx->rtimeoutms : 10000))) {
01690 return 't';
01691 }
01692 return res;
01693 case AST_ACTION_CALLBACK:
01694 ivr_func = option->adata;
01695 res = ivr_func(chan, cbdata);
01696 return res;
01697 case AST_ACTION_TRANSFER:
01698 res = ast_parseable_goto(chan, option->adata);
01699 return 0;
01700 case AST_ACTION_PLAYLIST:
01701 case AST_ACTION_BACKLIST:
01702 res = 0;
01703 c = ast_strdupa(option->adata);
01704 while ((n = strsep(&c, ";"))) {
01705 if ((res = ast_stream_and_wait(chan, n,
01706 (option->action == AST_ACTION_BACKLIST) ? AST_DIGIT_ANY : ""))) {
01707 break;
01708 }
01709 }
01710 ast_stopstream(chan);
01711 return res;
01712 default:
01713 ast_log(LOG_NOTICE, "Unknown dispatch function %d, ignoring!\n", option->action);
01714 return 0;
01715 }
01716 return -1;
01717 }
01718
01719 static int option_exists(struct ast_ivr_menu *menu, char *option)
01720 {
01721 int x;
01722 for (x = 0; menu->options[x].option; x++) {
01723 if (!strcasecmp(menu->options[x].option, option)) {
01724 return x;
01725 }
01726 }
01727 return -1;
01728 }
01729
01730 static int option_matchmore(struct ast_ivr_menu *menu, char *option)
01731 {
01732 int x;
01733 for (x = 0; menu->options[x].option; x++) {
01734 if ((!strncasecmp(menu->options[x].option, option, strlen(option))) &&
01735 (menu->options[x].option[strlen(option)])) {
01736 return x;
01737 }
01738 }
01739 return -1;
01740 }
01741
01742 static int read_newoption(struct ast_channel *chan, struct ast_ivr_menu *menu, char *exten, int maxexten)
01743 {
01744 int res = 0;
01745 int ms;
01746 while (option_matchmore(menu, exten)) {
01747 ms = chan->pbx ? chan->pbx->dtimeoutms : 5000;
01748 if (strlen(exten) >= maxexten - 1) {
01749 break;
01750 }
01751 if ((res = ast_waitfordigit(chan, ms)) < 1) {
01752 break;
01753 }
01754 exten[strlen(exten) + 1] = '\0';
01755 exten[strlen(exten)] = res;
01756 }
01757 return res > 0 ? 0 : res;
01758 }
01759
01760 static int ast_ivr_menu_run_internal(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01761 {
01762
01763 int res = 0;
01764 int pos = 0;
01765 int retries = 0;
01766 char exten[AST_MAX_EXTENSION] = "s";
01767 if (option_exists(menu, "s") < 0) {
01768 strcpy(exten, "g");
01769 if (option_exists(menu, "g") < 0) {
01770 ast_log(LOG_WARNING, "No 's' nor 'g' extension in menu '%s'!\n", menu->title);
01771 return -1;
01772 }
01773 }
01774 while (!res) {
01775 while (menu->options[pos].option) {
01776 if (!strcasecmp(menu->options[pos].option, exten)) {
01777 res = ivr_dispatch(chan, menu->options + pos, exten, cbdata);
01778 ast_debug(1, "IVR Dispatch of '%s' (pos %d) yields %d\n", exten, pos, res);
01779 if (res < 0) {
01780 break;
01781 } else if (res & RES_UPONE) {
01782 return 0;
01783 } else if (res & RES_EXIT) {
01784 return res;
01785 } else if (res & RES_REPEAT) {
01786 int maxretries = res & 0xffff;
01787 if ((res & RES_RESTART) == RES_RESTART) {
01788 retries = 0;
01789 } else {
01790 retries++;
01791 }
01792 if (!maxretries) {
01793 maxretries = 3;
01794 }
01795 if ((maxretries > 0) && (retries >= maxretries)) {
01796 ast_debug(1, "Max retries %d exceeded\n", maxretries);
01797 return -2;
01798 } else {
01799 if (option_exists(menu, "g") > -1) {
01800 strcpy(exten, "g");
01801 } else if (option_exists(menu, "s") > -1) {
01802 strcpy(exten, "s");
01803 }
01804 }
01805 pos = 0;
01806 continue;
01807 } else if (res && strchr(AST_DIGIT_ANY, res)) {
01808 ast_debug(1, "Got start of extension, %c\n", res);
01809 exten[1] = '\0';
01810 exten[0] = res;
01811 if ((res = read_newoption(chan, menu, exten, sizeof(exten)))) {
01812 break;
01813 }
01814 if (option_exists(menu, exten) < 0) {
01815 if (option_exists(menu, "i")) {
01816 ast_debug(1, "Invalid extension entered, going to 'i'!\n");
01817 strcpy(exten, "i");
01818 pos = 0;
01819 continue;
01820 } else {
01821 ast_debug(1, "Aborting on invalid entry, with no 'i' option!\n");
01822 res = -2;
01823 break;
01824 }
01825 } else {
01826 ast_debug(1, "New existing extension: %s\n", exten);
01827 pos = 0;
01828 continue;
01829 }
01830 }
01831 }
01832 pos++;
01833 }
01834 ast_debug(1, "Stopping option '%s', res is %d\n", exten, res);
01835 pos = 0;
01836 if (!strcasecmp(exten, "s")) {
01837 strcpy(exten, "g");
01838 } else {
01839 break;
01840 }
01841 }
01842 return res;
01843 }
01844
01845 int ast_ivr_menu_run(struct ast_channel *chan, struct ast_ivr_menu *menu, void *cbdata)
01846 {
01847 int res = ast_ivr_menu_run_internal(chan, menu, cbdata);
01848
01849 return res > 0 ? 0 : res;
01850 }
01851
01852 char *ast_read_textfile(const char *filename)
01853 {
01854 int fd, count = 0, res;
01855 char *output = NULL;
01856 struct stat filesize;
01857
01858 if (stat(filename, &filesize) == -1) {
01859 ast_log(LOG_WARNING, "Error can't stat %s\n", filename);
01860 return NULL;
01861 }
01862
01863 count = filesize.st_size + 1;
01864
01865 if ((fd = open(filename, O_RDONLY)) < 0) {
01866 ast_log(LOG_WARNING, "Cannot open file '%s' for reading: %s\n", filename, strerror(errno));
01867 return NULL;
01868 }
01869
01870 if ((output = ast_malloc(count))) {
01871 res = read(fd, output, count - 1);
01872 if (res == count - 1) {
01873 output[res] = '\0';
01874 } else {
01875 ast_log(LOG_WARNING, "Short read of %s (%d of %d): %s\n", filename, res, count - 1, strerror(errno));
01876 ast_free(output);
01877 output = NULL;
01878 }
01879 }
01880
01881 close(fd);
01882
01883 return output;
01884 }
01885
01886 static int parse_options(const struct ast_app_option *options, void *_flags, char **args, char *optstr, int flaglen)
01887 {
01888 char *s, *arg;
01889 int curarg, res = 0;
01890 unsigned int argloc;
01891 struct ast_flags *flags = _flags;
01892 struct ast_flags64 *flags64 = _flags;
01893
01894 if (flaglen == 32) {
01895 ast_clear_flag(flags, AST_FLAGS_ALL);
01896 } else {
01897 flags64->flags = 0;
01898 }
01899
01900 if (!optstr) {
01901 return 0;
01902 }
01903
01904 s = optstr;
01905 while (*s) {
01906 curarg = *s++ & 0x7f;
01907 argloc = options[curarg].arg_index;
01908 if (*s == '(') {
01909 int paren = 1, quote = 0;
01910 int parsequotes = (s[1] == '"') ? 1 : 0;
01911
01912
01913 arg = ++s;
01914 for (; *s; s++) {
01915 if (*s == '(' && !quote) {
01916 paren++;
01917 } else if (*s == ')' && !quote) {
01918
01919 paren--;
01920 } else if (*s == '"' && parsequotes) {
01921
01922 quote = quote ? 0 : 1;
01923 ast_copy_string(s, s + 1, INT_MAX);
01924 s--;
01925 } else if (*s == '\\') {
01926 if (!quote) {
01927
01928 ast_copy_string(s, s + 1, INT_MAX);
01929 } else if (quote && s[1] == '"') {
01930
01931 ast_copy_string(s, s + 1, INT_MAX);
01932 } else {
01933
01934 s++;
01935 }
01936 }
01937
01938 if (paren == 0) {
01939 break;
01940 }
01941 }
01942
01943 if ((s = strchr(s, ')'))) {
01944 if (argloc) {
01945 args[argloc - 1] = arg;
01946 }
01947 *s++ = '\0';
01948 } else {
01949 ast_log(LOG_WARNING, "Missing closing parenthesis for argument '%c' in string '%s'\n", curarg, arg);
01950 res = -1;
01951 break;
01952 }
01953 } else if (argloc) {
01954 args[argloc - 1] = "";
01955 }
01956 if (flaglen == 32) {
01957 ast_set_flag(flags, options[curarg].flag);
01958 } else {
01959 ast_set_flag64(flags64, options[curarg].flag);
01960 }
01961 }
01962
01963 return res;
01964 }
01965
01966 int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
01967 {
01968 return parse_options(options, flags, args, optstr, 32);
01969 }
01970
01971 int ast_app_parse_options64(const struct ast_app_option *options, struct ast_flags64 *flags, char **args, char *optstr)
01972 {
01973 return parse_options(options, flags, args, optstr, 64);
01974 }
01975
01976 void ast_app_options2str64(const struct ast_app_option *options, struct ast_flags64 *flags, char *buf, size_t len)
01977 {
01978 unsigned int i, found = 0;
01979 for (i = 32; i < 128 && found < len; i++) {
01980 if (ast_test_flag64(flags, options[i].flag)) {
01981 buf[found++] = i;
01982 }
01983 }
01984 buf[found] = '\0';
01985 }
01986
01987 int ast_get_encoded_char(const char *stream, char *result, size_t *consumed)
01988 {
01989 int i;
01990 *consumed = 1;
01991 *result = 0;
01992 if (ast_strlen_zero(stream)) {
01993 *consumed = 0;
01994 return -1;
01995 }
01996
01997 if (*stream == '\\') {
01998 *consumed = 2;
01999 switch (*(stream + 1)) {
02000 case 'n':
02001 *result = '\n';
02002 break;
02003 case 'r':
02004 *result = '\r';
02005 break;
02006 case 't':
02007 *result = '\t';
02008 break;
02009 case 'x':
02010
02011 if (strchr("0123456789ABCDEFabcdef", *(stream + 2)) && *(stream + 2) != '\0') {
02012 *consumed = 3;
02013 if (*(stream + 2) <= '9') {
02014 *result = *(stream + 2) - '0';
02015 } else if (*(stream + 2) <= 'F') {
02016 *result = *(stream + 2) - 'A' + 10;
02017 } else {
02018 *result = *(stream + 2) - 'a' + 10;
02019 }
02020 } else {
02021 ast_log(LOG_ERROR, "Illegal character '%c' in hexadecimal string\n", *(stream + 2));
02022 return -1;
02023 }
02024
02025 if (strchr("0123456789ABCDEFabcdef", *(stream + 3)) && *(stream + 3) != '\0') {
02026 *consumed = 4;
02027 *result <<= 4;
02028 if (*(stream + 3) <= '9') {
02029 *result += *(stream + 3) - '0';
02030 } else if (*(stream + 3) <= 'F') {
02031 *result += *(stream + 3) - 'A' + 10;
02032 } else {
02033 *result += *(stream + 3) - 'a' + 10;
02034 }
02035 }
02036 break;
02037 case '0':
02038
02039 *consumed = 2;
02040 for (i = 2; ; i++) {
02041 if (strchr("01234567", *(stream + i)) && *(stream + i) != '\0') {
02042 (*consumed)++;
02043 ast_debug(5, "result was %d, ", *result);
02044 *result <<= 3;
02045 *result += *(stream + i) - '0';
02046 ast_debug(5, "is now %d\n", *result);
02047 } else {
02048 break;
02049 }
02050 }
02051 break;
02052 default:
02053 *result = *(stream + 1);
02054 }
02055 } else {
02056 *result = *stream;
02057 *consumed = 1;
02058 }
02059 return 0;
02060 }
02061
02062 char *ast_get_encoded_str(const char *stream, char *result, size_t result_size)
02063 {
02064 char *cur = result;
02065 size_t consumed;
02066
02067 while (cur < result + result_size - 1 && !ast_get_encoded_char(stream, cur, &consumed)) {
02068 cur++;
02069 stream += consumed;
02070 }
02071 *cur = '\0';
02072 return result;
02073 }
02074
02075 int ast_str_get_encoded_str(struct ast_str **str, int maxlen, const char *stream)
02076 {
02077 char next, *buf;
02078 size_t offset = 0;
02079 size_t consumed;
02080
02081 if (strchr(stream, '\\')) {
02082 while (!ast_get_encoded_char(stream, &next, &consumed)) {
02083 if (offset + 2 > ast_str_size(*str) && maxlen > -1) {
02084 ast_str_make_space(str, maxlen > 0 ? maxlen : (ast_str_size(*str) + 48) * 2 - 48);
02085 }
02086 if (offset + 2 > ast_str_size(*str)) {
02087 break;
02088 }
02089 buf = ast_str_buffer(*str);
02090 buf[offset++] = next;
02091 stream += consumed;
02092 }
02093 buf = ast_str_buffer(*str);
02094 buf[offset++] = '\0';
02095 ast_str_update(*str);
02096 } else {
02097 ast_str_set(str, maxlen, "%s", stream);
02098 }
02099 return 0;
02100 }
02101
02102 void ast_close_fds_above_n(int n)
02103 {
02104 closefrom(n + 1);
02105 }
02106
02107 int ast_safe_fork(int stop_reaper)
02108 {
02109 sigset_t signal_set, old_set;
02110 int pid;
02111
02112
02113 if (stop_reaper) {
02114 ast_replace_sigchld();
02115 }
02116
02117 sigfillset(&signal_set);
02118 pthread_sigmask(SIG_BLOCK, &signal_set, &old_set);
02119
02120 pid = fork();
02121
02122 if (pid != 0) {
02123
02124 pthread_sigmask(SIG_SETMASK, &old_set, NULL);
02125 if (!stop_reaper && pid > 0) {
02126 struct zombie *cur = ast_calloc(1, sizeof(*cur));
02127 if (cur) {
02128 cur->pid = pid;
02129 AST_LIST_LOCK(&zombies);
02130 AST_LIST_INSERT_TAIL(&zombies, cur, list);
02131 AST_LIST_UNLOCK(&zombies);
02132 if (shaun_of_the_dead_thread == AST_PTHREADT_NULL) {
02133 if (ast_pthread_create_background(&shaun_of_the_dead_thread, NULL, shaun_of_the_dead, NULL)) {
02134 ast_log(LOG_ERROR, "Shaun of the Dead wants to kill zombies, but can't?!!\n");
02135 shaun_of_the_dead_thread = AST_PTHREADT_NULL;
02136 }
02137 }
02138 }
02139 }
02140 return pid;
02141 } else {
02142
02143 #ifdef HAVE_CAP
02144 cap_t cap = cap_from_text("cap_net_admin-eip");
02145
02146 if (cap_set_proc(cap)) {
02147 ast_log(LOG_WARNING, "Unable to remove capabilities.\n");
02148 }
02149 cap_free(cap);
02150 #endif
02151
02152
02153 signal(SIGHUP, SIG_DFL);
02154 signal(SIGCHLD, SIG_DFL);
02155 signal(SIGINT, SIG_DFL);
02156 signal(SIGURG, SIG_DFL);
02157 signal(SIGTERM, SIG_DFL);
02158 signal(SIGPIPE, SIG_DFL);
02159 signal(SIGXFSZ, SIG_DFL);
02160
02161
02162 if (pthread_sigmask(SIG_UNBLOCK, &signal_set, NULL)) {
02163 ast_log(LOG_WARNING, "unable to unblock signals: %s\n", strerror(errno));
02164 _exit(1);
02165 }
02166
02167 return pid;
02168 }
02169 }
02170
02171 void ast_safe_fork_cleanup(void)
02172 {
02173 ast_unreplace_sigchld();
02174 }
02175
02176 int ast_app_parse_timelen(const char *timestr, int *result, enum ast_timelen unit)
02177 {
02178 int res;
02179 char u[10];
02180 #ifdef HAVE_LONG_DOUBLE_WIDER
02181 long double amount;
02182 #define FMT "%30Lf%9s"
02183 #else
02184 double amount;
02185 #define FMT "%30lf%9s"
02186 #endif
02187 if (!timestr) {
02188 return -1;
02189 }
02190
02191 if ((res = sscanf(timestr, FMT, &amount, u)) == 0) {
02192 #undef FMT
02193 return -1;
02194 } else if (res == 2) {
02195 switch (u[0]) {
02196 case 'h':
02197 case 'H':
02198 unit = TIMELEN_HOURS;
02199 break;
02200 case 's':
02201 case 'S':
02202 unit = TIMELEN_SECONDS;
02203 break;
02204 case 'm':
02205 case 'M':
02206 if (toupper(u[1]) == 'S') {
02207 unit = TIMELEN_MILLISECONDS;
02208 } else if (u[1] == '\0') {
02209 unit = TIMELEN_MINUTES;
02210 }
02211 break;
02212 }
02213 }
02214
02215 switch (unit) {
02216 case TIMELEN_HOURS:
02217 amount *= 60;
02218
02219 case TIMELEN_MINUTES:
02220 amount *= 60;
02221
02222 case TIMELEN_SECONDS:
02223 amount *= 1000;
02224
02225 case TIMELEN_MILLISECONDS:
02226 ;
02227 }
02228 *result = amount > INT_MAX ? INT_MAX : (int) amount;
02229 return 0;
02230 }
02231