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