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