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