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