Newer
Older
ast_channel_lock(peer);
ast_channel_stage_snapshot(peer);
ast_clear_flag(ast_channel_flags(peer), AST_FLAG_OUTGOING);
ast_channel_context_set(peer, ast_channel_context(chan));
ast_channel_exten_set(peer, ast_channel_exten(chan));
ast_channel_priority_set(peer, ast_channel_priority(chan) + 2);
ast_channel_stage_snapshot_done(peer);
ast_channel_unlock(peer);
Richard Mudgett
committed
if (ast_pbx_start(peer)) {
Richard Mudgett
committed
ast_autoservice_chan_hangup_peer(chan, peer);
Richard Mudgett
committed
}
if (continue_exec)
*continue_exec = 1;
res = 0;
Matthew Jordan
committed
ast_channel_publish_dial(chan, peer, NULL, "ANSWER");
goto done;
if (ast_test_flag64(&opts, OPT_CALLEE_MACRO) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_MACRO])) {
const char *macro_result_peer;
Matthew Jordan
committed
int macro_res;
/* Set peer->exten and peer->context so that MACRO_EXTEN and MACRO_CONTEXT get set */
ast_channel_lock_both(chan, peer);
ast_channel_context_set(peer, ast_channel_context(chan));
ast_channel_exten_set(peer, ast_channel_exten(chan));
ast_channel_unlock(peer);
ast_channel_unlock(chan);
ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_MACRO]);
Matthew Jordan
committed
macro_res = ast_app_exec_macro(chan, peer, opt_args[OPT_ARG_CALLEE_MACRO]);
ast_channel_lock(peer);
Matthew Jordan
committed
if (!macro_res && (macro_result_peer = pbx_builtin_getvar_helper(peer, "MACRO_RESULT"))) {
char *macro_result = ast_strdupa(macro_result_peer);
char *macro_transfer_dest;
ast_channel_unlock(peer);
if (!strcasecmp(macro_result, "BUSY")) {
ast_copy_string(pa.status, macro_result, sizeof(pa.status));
ast_set_flag64(peerflags, OPT_GO_ON);
Matthew Jordan
committed
macro_res = -1;
} else if (!strcasecmp(macro_result, "CONGESTION") || !strcasecmp(macro_result, "CHANUNAVAIL")) {
ast_copy_string(pa.status, macro_result, sizeof(pa.status));
Matthew Jordan
committed
macro_res = -1;
} else if (!strcasecmp(macro_result, "CONTINUE")) {
/* hangup peer and keep chan alive assuming the macro has changed
the context / exten / priority or perhaps
the next priority in the current exten is desired.
*/
Matthew Jordan
committed
macro_res = -1;
} else if (!strcasecmp(macro_result, "ABORT")) {
/* Hangup both ends unless the caller has the g flag */
Matthew Jordan
committed
macro_res = -1;
} else if (!strncasecmp(macro_result, "GOTO:", 5)) {
macro_transfer_dest = macro_result + 5;
Matthew Jordan
committed
macro_res = -1;
/* perform a transfer to a new extension */
if (strchr(macro_transfer_dest, '^')) { /* context^exten^priority*/
ast_replace_subargument_delimiter(macro_transfer_dest);
}
if (!ast_parseable_goto(chan, macro_transfer_dest)) {
ast_set_flag64(peerflags, OPT_GO_ON);
Matthew Jordan
committed
if (macro_res && !dial_end_raised) {
ast_channel_publish_dial(chan, peer, NULL, macro_result);
dial_end_raised = 1;
}
} else {
ast_channel_unlock(peer);
Matthew Jordan
committed
res = macro_res;
if (ast_test_flag64(&opts, OPT_CALLEE_GOSUB) && !ast_strlen_zero(opt_args[OPT_ARG_CALLEE_GOSUB])) {
const char *gosub_result_peer;
char *gosub_argstart;
char *gosub_args = NULL;
Matthew Jordan
committed
int gosub_res = -1;
Steve Murphy
committed
ast_replace_subargument_delimiter(opt_args[OPT_ARG_CALLEE_GOSUB]);
gosub_argstart = strchr(opt_args[OPT_ARG_CALLEE_GOSUB], ',');
if (gosub_argstart) {
const char *what_is_s = "s";
*gosub_argstart = 0;
if (!ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
what_is_s = "~~s~~";
if (ast_asprintf(&gosub_args, "%s,%s,1(%s)", opt_args[OPT_ARG_CALLEE_GOSUB], what_is_s, gosub_argstart + 1) < 0) {
gosub_args = NULL;
}
*gosub_argstart = ',';
} else {
const char *what_is_s = "s";
if (!ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "s", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL)) &&
ast_exists_extension(peer, opt_args[OPT_ARG_CALLEE_GOSUB], "~~s~~", 1, S_COR(ast_channel_caller(peer)->id.number.valid, ast_channel_caller(peer)->id.number.str, NULL))) {
what_is_s = "~~s~~";
}
if (ast_asprintf(&gosub_args, "%s,%s,1", opt_args[OPT_ARG_CALLEE_GOSUB], what_is_s) < 0) {
gosub_args = NULL;
Mark Michelson
committed
}
Steve Murphy
committed
}
if (gosub_args) {
Matthew Jordan
committed
gosub_res = ast_app_exec_sub(chan, peer, gosub_args, 0);
ast_free(gosub_args);
} else {
ast_log(LOG_ERROR, "Could not Allocate string for Gosub arguments -- Gosub Call Aborted!\n");
Steve Murphy
committed
}
ast_channel_lock_both(chan, peer);
Matthew Jordan
committed
if (!gosub_res && (gosub_result_peer = pbx_builtin_getvar_helper(peer, "GOSUB_RESULT"))) {
Steve Murphy
committed
char *gosub_transfer_dest;
char *gosub_result = ast_strdupa(gosub_result_peer);
const char *gosub_retval = pbx_builtin_getvar_helper(peer, "GOSUB_RETVAL");
/* Inherit return value from the peer, so it can be used in the master */
if (gosub_retval) {
pbx_builtin_setvar_helper(chan, "GOSUB_RETVAL", gosub_retval);
}
Steve Murphy
committed
ast_channel_unlock(peer);
ast_channel_unlock(chan);
Steve Murphy
committed
if (!strcasecmp(gosub_result, "BUSY")) {
ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
ast_set_flag64(peerflags, OPT_GO_ON);
Matthew Jordan
committed
gosub_res = -1;
Steve Murphy
committed
} else if (!strcasecmp(gosub_result, "CONGESTION") || !strcasecmp(gosub_result, "CHANUNAVAIL")) {
ast_copy_string(pa.status, gosub_result, sizeof(pa.status));
Matthew Jordan
committed
gosub_res = -1;
Steve Murphy
committed
} else if (!strcasecmp(gosub_result, "CONTINUE")) {
/* Hangup peer and continue with the next extension priority. */
Matthew Jordan
committed
gosub_res = -1;
Steve Murphy
committed
} else if (!strcasecmp(gosub_result, "ABORT")) {
/* Hangup both ends unless the caller has the g flag */
Matthew Jordan
committed
gosub_res = -1;
} else if (!strncasecmp(gosub_result, "GOTO:", 5)) {
gosub_transfer_dest = gosub_result + 5;
Matthew Jordan
committed
gosub_res = -1;
Steve Murphy
committed
/* perform a transfer to a new extension */
if (strchr(gosub_transfer_dest, '^')) { /* context^exten^priority*/
ast_replace_subargument_delimiter(gosub_transfer_dest);
}
if (!ast_parseable_goto(chan, gosub_transfer_dest)) {
ast_set_flag64(peerflags, OPT_GO_ON);
Steve Murphy
committed
}
}
Matthew Jordan
committed
if (gosub_res) {
res = gosub_res;
if (!dial_end_raised) {
ast_channel_publish_dial(chan, peer, NULL, gosub_result);
dial_end_raised = 1;
}
}
} else {
ast_channel_unlock(peer);
ast_channel_unlock(chan);
Steve Murphy
committed
}
}
Matthew Jordan
committed
/* None of the Dial options changed our status; inform
* everyone that this channel answered
*/
Matthew Jordan
committed
if (!dial_end_raised) {
ast_channel_publish_dial(chan, peer, NULL, "ANSWER");
dial_end_raised = 1;
}
Matthew Jordan
committed
if (!ast_tvzero(calldurationlimit)) {
struct timeval whentohangup = ast_tvadd(ast_tvnow(), calldurationlimit);
ast_channel_lock(peer);
ast_channel_whentohangup_set(peer, &whentohangup);
ast_channel_unlock(peer);
ast_verb(3, "Sending DTMF '%s' to the called party.\n", dtmfcalled);
Tilghman Lesher
committed
res = ast_dtmf_stream(peer, chan, dtmfcalled, 250, 0);
if (!ast_strlen_zero(dtmfcalling)) {
ast_verb(3, "Sending DTMF '%s' to the calling party.\n", dtmfcalling);
Tilghman Lesher
committed
res = ast_dtmf_stream(chan, peer, dtmfcalling, 250, 0);
Terry Wilson
committed
Richard Mudgett
committed
if (!ast_check_hangup(chan) && ast_check_hangup(peer)) {
ast_channel_hangupcause_set(chan, ast_channel_hangupcause(peer));
}
setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
if (ast_bridge_setup_after_goto(peer)
Richard Mudgett
committed
|| ast_pbx_start(peer)) {
ast_autoservice_chan_hangup_peer(chan, peer);
}
res = -1;
} else {
if (ast_test_flag64(peerflags, OPT_CALLEE_TRANSFER))
ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT);
if (ast_test_flag64(peerflags, OPT_CALLER_TRANSFER))
ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT);
if (ast_test_flag64(peerflags, OPT_CALLEE_HANGUP))
ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT);
if (ast_test_flag64(peerflags, OPT_CALLER_HANGUP))
ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT);
if (ast_test_flag64(peerflags, OPT_CALLEE_MONITOR))
ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMON);
if (ast_test_flag64(peerflags, OPT_CALLER_MONITOR))
ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMON);
if (ast_test_flag64(peerflags, OPT_CALLEE_PARK))
ast_set_flag(&(config.features_callee), AST_FEATURE_PARKCALL);
if (ast_test_flag64(peerflags, OPT_CALLER_PARK))
ast_set_flag(&(config.features_caller), AST_FEATURE_PARKCALL);
if (ast_test_flag64(peerflags, OPT_CALLEE_MIXMONITOR))
ast_set_flag(&(config.features_callee), AST_FEATURE_AUTOMIXMON);
if (ast_test_flag64(peerflags, OPT_CALLER_MIXMONITOR))
ast_set_flag(&(config.features_caller), AST_FEATURE_AUTOMIXMON);
Terry Wilson
committed
config.end_bridge_callback = end_bridge_callback;
config.end_bridge_callback_data = chan;
config.end_bridge_callback_data_fixup = end_bridge_callback_data_fixup;
if (moh) {
moh = 0;
ast_moh_stop(chan);
} else if (sentringing) {
sentringing = 0;
ast_indicate(chan, -1);
}
/* Be sure no generators are left on it and reset the visible indication */
Mark Spencer
committed
ast_deactivate_generator(chan);
ast_channel_visible_indication_set(chan, 0);
Mark Spencer
committed
/* Make sure channels are compatible */
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n", ast_channel_name(chan), ast_channel_name(peer));
Richard Mudgett
committed
ast_autoservice_chan_hangup_peer(chan, peer);
Mark Spencer
committed
}
if (opermode) {
struct oprmode oprmode;
oprmode.peer = peer;
oprmode.mode = opermode;
ast_channel_setoption(chan, AST_OPTION_OPRMODE, &oprmode, sizeof(oprmode), 0);
}
Richard Mudgett
committed
setup_peer_after_bridge_goto(chan, peer, &opts, opt_args);
Tilghman Lesher
committed
res = ast_bridge_call(chan, peer, &config);
if (moh) {
moh = 0;
ast_moh_stop(chan);
} else if (sentringing) {
sentringing = 0;
ast_indicate(chan, -1);
}
if (delprivintro && ast_fileexists(pa.privintro, NULL, NULL) > 0) {
ast_filedelete(pa.privintro, NULL);
if (ast_fileexists(pa.privintro, NULL, NULL) > 0) {
ast_log(LOG_NOTICE, "privacy: ast_filedelete didn't do its job on %s\n", pa.privintro);
} else {
ast_verb(3, "Successfully deleted %s intro file\n", pa.privintro);
}
}
ast_channel_early_bridge(chan, NULL);
/* forward 'answered elsewhere' if we received it */
hanguptree(&out_chans, NULL,
ast_channel_hangupcause(chan) == AST_CAUSE_ANSWERED_ELSEWHERE
|| ast_test_flag64(&opts, OPT_CANCEL_ELSEWHERE)
? AST_CAUSE_ANSWERED_ELSEWHERE : -1);
pbx_builtin_setvar_helper(chan, "DIALSTATUS", pa.status);
ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status);
if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_INCOMPLETE)) {
if (!ast_tvzero(calldurationlimit))
memset(ast_channel_whentohangup(chan), 0, sizeof(*ast_channel_whentohangup(chan)));
done:
Tilghman Lesher
committed
if (config.warning_sound) {
ast_free((char *)config.warning_sound);
}
if (config.end_sound) {
ast_free((char *)config.end_sound);
}
if (config.start_sound) {
ast_free((char *)config.start_sound);
}
static int dial_exec(struct ast_channel *chan, const char *data)
struct ast_flags64 peerflags;
memset(&peerflags, 0, sizeof(peerflags));
return dial_exec_full(chan, data, &peerflags, NULL);
static int retrydial_exec(struct ast_channel *chan, const char *data)
Tilghman Lesher
committed
char *parse;
const char *context = NULL;
int sleepms = 0, loops = 0, res = -1;
Tilghman Lesher
committed
struct ast_flags64 peerflags = { 0, };
AST_DECLARE_APP_ARGS(args,
AST_APP_ARG(announce);
AST_APP_ARG(sleep);
AST_APP_ARG(retries);
AST_APP_ARG(dialdata);
);
if (ast_strlen_zero(data)) {
Russell Bryant
committed
ast_log(LOG_WARNING, "RetryDial requires an argument!\n");
return -1;
Tilghman Lesher
committed
parse = ast_strdupa(data);
AST_STANDARD_APP_ARGS(args, parse);
Russell Bryant
committed
Joshua Colp
committed
if (!ast_strlen_zero(args.sleep) && (sleepms = atoi(args.sleep)))
sleepms *= 1000;
Tilghman Lesher
committed
Joshua Colp
committed
if (!ast_strlen_zero(args.retries)) {
loops = atoi(args.retries);
}
Tilghman Lesher
committed
if (!args.dialdata) {
ast_log(LOG_ERROR, "%s requires a 4th argument (dialdata)\n", rapp);
goto done;
if (sleepms < 1000)
sleepms = 10000;
ast_channel_lock(chan);
context = pbx_builtin_getvar_helper(chan, "EXITCONTEXT");
context = !ast_strlen_zero(context) ? ast_strdupa(context) : NULL;
ast_channel_unlock(chan);
res = 0;
ast_channel_data_set(chan, "Retrying");
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
ast_moh_stop(chan);
Tilghman Lesher
committed
res = dial_exec_full(chan, args.dialdata, &peerflags, &continue_exec);
if (ast_test_flag64(&peerflags, OPT_DTMF_EXIT)) {
Tilghman Lesher
committed
if (!ast_strlen_zero(args.announce)) {
if (ast_fileexists(args.announce, NULL, ast_channel_language(chan)) > 0) {
if (!(res = ast_streamfile(chan, args.announce, ast_channel_language(chan))))
ast_waitstream(chan, AST_DIGIT_ANY);
} else
Tilghman Lesher
committed
ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
if (!res && sleepms) {
if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
Kevin P. Fleming
committed
ast_moh_start(chan, NULL, NULL);
res = ast_waitfordigit(chan, sleepms);
Tilghman Lesher
committed
if (!ast_strlen_zero(args.announce)) {
if (ast_fileexists(args.announce, NULL, ast_channel_language(chan)) > 0) {
if (!(res = ast_streamfile(chan, args.announce, ast_channel_language(chan))))
res = ast_waitstream(chan, "");
} else
Tilghman Lesher
committed
ast_log(LOG_WARNING, "Announce file \"%s\" specified in Retrydial does not exist\n", args.announce);
if (sleepms) {
if (!ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
Kevin P. Fleming
committed
ast_moh_start(chan, NULL, NULL);
res = ast_waitfordigit(chan, sleepms);
if (res < 0 || res == AST_PBX_INCOMPLETE) {
} else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */
Kevin P. Fleming
committed
if (onedigit_goto(chan, context, (char) res, 1)) {
res = 0;
break;
}
}
loops--;
}
if (loops == 0)
res = 0;
else if (res == 1)
res = 0;
if (ast_test_flag(ast_channel_flags(chan), AST_FLAG_MOH))
return res;
static int unload_module(void)
Russell Bryant
committed
int res;
res = ast_unregister_application(app);
res |= ast_unregister_application(rapp);
return res;
static int load_module(void)
Russell Bryant
committed
res = ast_register_application_xml(app, dial_exec);
res |= ast_register_application_xml(rapp, retrydial_exec);
AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_DEFAULT, "Dialing Application",
.support_level = AST_MODULE_SUPPORT_CORE,
.load = load_module,
.unload = unload_module,
.requires = "ccss",
);