summaryrefslogtreecommitdiff
path: root/main/features.c
diff options
context:
space:
mode:
Diffstat (limited to 'main/features.c')
-rw-r--r--main/features.c139
1 files changed, 58 insertions, 81 deletions
diff --git a/main/features.c b/main/features.c
index 79d1036f2..b602dbb98 100644
--- a/main/features.c
+++ b/main/features.c
@@ -1077,10 +1077,10 @@ static void *bridge_call_thread(void *data)
ast_log(LOG_VERBOSE, "putting peer %s into PBX again\n", ast_channel_name(tobj->peer));
if (ast_pbx_start(tobj->peer)) {
ast_log(LOG_WARNING, "FAILED continuing PBX on peer %s\n", ast_channel_name(tobj->peer));
- ast_hangup(tobj->peer);
+ ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
}
} else {
- ast_hangup(tobj->peer);
+ ast_autoservice_chan_hangup_peer(tobj->chan, tobj->peer);
}
if (!ast_check_hangup(tobj->chan)) {
ast_log(LOG_VERBOSE, "putting chan %s into PBX again\n", ast_channel_name(tobj->chan));
@@ -2526,7 +2526,7 @@ static int check_compat(struct ast_channel *c, struct ast_channel *newchan)
if (ast_channel_make_compatible(c, newchan) < 0) {
ast_log(LOG_WARNING, "Had to drop call because I couldn't make %s compatible with %s\n",
ast_channel_name(c), ast_channel_name(newchan));
- ast_hangup(newchan);
+ ast_autoservice_chan_hangup_peer(c, newchan);
return -1;
}
return 0;
@@ -2762,7 +2762,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
}
if (ast_check_hangup(newchan) || !ast_check_hangup(transferer)) {
- ast_hangup(newchan);
+ ast_autoservice_chan_hangup_peer(transferer, newchan);
if (ast_stream_and_wait(transferer, xfersound, "")) {
ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
}
@@ -2882,7 +2882,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
/* newchan is up, we should prepare transferee and bridge them */
if (ast_check_hangup(newchan)) {
- ast_hangup(newchan);
+ ast_autoservice_chan_hangup_peer(transferee, newchan);
ast_party_connected_line_free(&connected_line);
return -1;
}
@@ -2908,7 +2908,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", ast_channel_linkedid(transferee), 0, "Transfered/%s", ast_channel_name(transferee));
if (!xferchan) {
- ast_hangup(newchan);
+ ast_autoservice_chan_hangup_peer(transferee, newchan);
ast_party_connected_line_free(&connected_line);
return -1;
}
@@ -2922,7 +2922,7 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
if (ast_channel_masquerade(xferchan, transferee)) {
ast_hangup(xferchan);
- ast_hangup(newchan);
+ ast_autoservice_chan_hangup_peer(transferee, newchan);
ast_party_connected_line_free(&connected_line);
return -1;
}
@@ -4169,7 +4169,6 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct a
int diff;
int hasfeatures=0;
int hadfeatures=0;
- int autoloopflag;
int sendingdtmfdigit = 0;
int we_disabled_peer_cdr = 0;
struct ast_option_header *aoh;
@@ -4179,7 +4178,8 @@ int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, struct a
struct ast_cdr *new_chan_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
struct ast_cdr *new_peer_cdr = NULL; /* the proper chan cdr, if there are forked cdrs */
struct ast_silence_generator *silgen = NULL;
- const char *h_context;
+ /*! TRUE if h-exten or hangup handlers run. */
+ int hangup_run = 0;
pbx_builtin_setvar_helper(chan, "BRIDGEPEER", ast_channel_name(peer));
pbx_builtin_setvar_helper(peer, "BRIDGEPEER", ast_channel_name(chan));
@@ -4611,105 +4611,82 @@ before_you_go:
config->end_bridge_callback(config->end_bridge_callback_data);
}
- /* run the hangup exten on the chan object IFF it was NOT involved in a parking situation
- * if it were, then chan belongs to a different thread now, and might have been hung up long
- * ago.
- */
- if (ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
- h_context = NULL;
- } else if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1,
- S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
- h_context = ast_channel_context(chan);
- } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
- && ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1,
- S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL))) {
- h_context = ast_channel_macrocontext(chan);
- } else {
- h_context = NULL;
- }
- if (h_context) {
+ if (!ast_test_flag(&config->features_caller, AST_FEATURE_NO_H_EXTEN)) {
struct ast_cdr *swapper = NULL;
char savelastapp[AST_MAX_EXTENSION];
char savelastdata[AST_MAX_EXTENSION];
char save_context[AST_MAX_CONTEXT];
char save_exten[AST_MAX_EXTENSION];
int save_prio;
- int found = 0; /* set if we find at least one match */
- int spawn_error = 0;
- /*
- * Make sure that the channel is marked as hungup since we are
- * going to run the "h" exten on it.
- */
- ast_softhangup(chan, AST_SOFTHANGUP_APPUNLOAD);
-
- autoloopflag = ast_test_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
- ast_set_flag(ast_channel_flags(chan), AST_FLAG_IN_AUTOLOOP);
- if (bridge_cdr && ast_opt_end_cdr_before_h_exten) {
- ast_cdr_end(bridge_cdr);
- }
-
- /* swap the bridge cdr and the chan cdr for a moment, and let the endbridge
- dialplan code operate on it */
ast_channel_lock(chan);
if (bridge_cdr) {
+ /*
+ * Swap the bridge_cdr and the chan cdr for a moment, and let
+ * the hangup dialplan code operate on it.
+ */
swapper = ast_channel_cdr(chan);
+ ast_channel_cdr_set(chan, bridge_cdr);
+
+ /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
ast_copy_string(savelastapp, bridge_cdr->lastapp, sizeof(bridge_cdr->lastapp));
ast_copy_string(savelastdata, bridge_cdr->lastdata, sizeof(bridge_cdr->lastdata));
- ast_channel_cdr_set(chan, bridge_cdr);
}
ast_copy_string(save_context, ast_channel_context(chan), sizeof(save_context));
ast_copy_string(save_exten, ast_channel_exten(chan), sizeof(save_exten));
save_prio = ast_channel_priority(chan);
- if (h_context != ast_channel_context(chan)) {
- ast_channel_context_set(chan, h_context);
- }
- ast_channel_exten_set(chan, "h");
- ast_channel_priority_set(chan, 1);
ast_channel_unlock(chan);
- while ((spawn_error = ast_spawn_extension(chan, ast_channel_context(chan), ast_channel_exten(chan),
- ast_channel_priority(chan),
- S_COR(ast_channel_caller(chan)->id.number.valid, ast_channel_caller(chan)->id.number.str, NULL),
- &found, 1)) == 0) {
- ast_channel_priority_set(chan, ast_channel_priority(chan) + 1);
- }
- if (found && spawn_error) {
- /* Something bad happened, or a hangup has been requested. */
- ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan));
- ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", ast_channel_context(chan), ast_channel_exten(chan), ast_channel_priority(chan), ast_channel_name(chan));
- }
+ ast_autoservice_start(peer);
+ if (ast_exists_extension(chan, ast_channel_context(chan), "h", 1,
+ S_COR(ast_channel_caller(chan)->id.number.valid,
+ ast_channel_caller(chan)->id.number.str, NULL))) {
+ ast_pbx_h_exten_run(chan, ast_channel_context(chan));
+ hangup_run = 1;
+ } else if (!ast_strlen_zero(ast_channel_macrocontext(chan))
+ && ast_exists_extension(chan, ast_channel_macrocontext(chan), "h", 1,
+ S_COR(ast_channel_caller(chan)->id.number.valid,
+ ast_channel_caller(chan)->id.number.str, NULL))) {
+ ast_pbx_h_exten_run(chan, ast_channel_macrocontext(chan));
+ hangup_run = 1;
+ }
+ if (ast_pbx_hangup_handler_run(chan)) {
+ /* Indicate hangup handlers were run. */
+ hangup_run = 1;
+ }
+ ast_autoservice_stop(peer);
- /* swap it back */
ast_channel_lock(chan);
+
+ /* swap it back */
ast_channel_context_set(chan, save_context);
ast_channel_exten_set(chan, save_exten);
ast_channel_priority_set(chan, save_prio);
if (bridge_cdr) {
if (ast_channel_cdr(chan) == bridge_cdr) {
ast_channel_cdr_set(chan, swapper);
+
+ /* Restore the lastapp/lastdata */
+ ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
+ ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
} else {
bridge_cdr = NULL;
}
}
- /* An "h" exten has been run, so indicate that one has been run. */
- ast_set_flag(ast_channel_flags(chan), AST_FLAG_BRIDGE_HANGUP_RUN);
ast_channel_unlock(chan);
-
- /* protect the lastapp/lastdata against the effects of the hangup/dialplan code */
- if (bridge_cdr) {
- ast_copy_string(bridge_cdr->lastapp, savelastapp, sizeof(bridge_cdr->lastapp));
- ast_copy_string(bridge_cdr->lastdata, savelastdata, sizeof(bridge_cdr->lastdata));
- }
- ast_set2_flag(ast_channel_flags(chan), autoloopflag, AST_FLAG_IN_AUTOLOOP);
}
/* obey the NoCDR() wishes. -- move the DISABLED flag to the bridge CDR if it was set on the channel during the bridge... */
new_chan_cdr = pick_unlocked_cdr(ast_channel_cdr(chan)); /* the proper chan cdr, if there are forked cdrs */
- /* If the channel CDR has been modified during the call, record the changes in the bridge cdr,
- * BUT, if we've gone through the h extension block above, the CDR got swapped so don't overwrite
- * what was done in the h extension. What a mess. This is why you never touch CDR code. */
- if (new_chan_cdr && bridge_cdr && !h_context) {
+
+ /*
+ * If the channel CDR has been modified during the call, record
+ * the changes in the bridge cdr, BUT, if hangup_run, the CDR
+ * got swapped so don't overwrite what was done in the
+ * h-extension or hangup handlers. What a mess. This is why
+ * you never touch CDR code.
+ */
+ if (new_chan_cdr && bridge_cdr && !hangup_run) {
ast_cdr_copy_vars(bridge_cdr, new_chan_cdr);
ast_copy_string(bridge_cdr->userfield, new_chan_cdr->userfield, sizeof(bridge_cdr->userfield));
bridge_cdr->amaflags = new_chan_cdr->amaflags;
@@ -5540,7 +5517,7 @@ static int parked_call_exec(struct ast_channel *chan, const char *data)
break;
}
if (res) {
- ast_hangup(peer);
+ ast_autoservice_chan_hangup_peer(chan, peer);
parkinglot_unref(parkinglot);
return -1;
}
@@ -5549,7 +5526,7 @@ static int parked_call_exec(struct ast_channel *chan, const char *data)
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", ast_channel_name(chan), ast_channel_name(peer));
- ast_hangup(peer);
+ ast_autoservice_chan_hangup_peer(chan, peer);
parkinglot_unref(parkinglot);
return -1;
}
@@ -5601,7 +5578,7 @@ static int parked_call_exec(struct ast_channel *chan, const char *data)
ast_cdr_setdestchan(ast_channel_cdr(chan), ast_channel_name(peer));
/* Simulate the PBX hanging up */
- ast_hangup(peer);
+ ast_autoservice_chan_hangup_peer(chan, peer);
} else {
if (ast_stream_and_wait(chan, "pbx-invalidpark", "")) {
ast_log(LOG_WARNING, "ast_streamfile of %s failed on %s\n", "pbx-invalidpark",
@@ -8014,7 +7991,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data)
"Channel2: %s\r\n", ast_channel_name(chan), ast_channel_name(final_dest_chan));
/* Maybe we should return this channel to the PBX? */
- ast_hangup(final_dest_chan);
+ ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
pbx_builtin_setvar_helper(chan, "BRIDGERESULT", "INCOMPATIBLE");
current_dest_chan = ast_channel_unref(current_dest_chan);
@@ -8088,7 +8065,7 @@ static int bridge_exec(struct ast_channel *chan, const char *data)
goto_opt = ast_goto_if_exists(final_dest_chan, caller_context, caller_extension, caller_priority + 1);
}
if (goto_opt || ast_pbx_start(final_dest_chan)) {
- ast_hangup(final_dest_chan);
+ ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
}
} else if (!ast_test_flag(&opts, OPT_CALLEE_KILL)) {
ast_debug(1, "starting new PBX in %s,%s,%d for chan %s\n",
@@ -8097,16 +8074,16 @@ static int bridge_exec(struct ast_channel *chan, const char *data)
if (ast_pbx_start(final_dest_chan)) {
ast_log(LOG_WARNING, "FAILED continuing PBX on dest chan %s\n", ast_channel_name(final_dest_chan));
- ast_hangup(final_dest_chan);
+ ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
} else {
ast_debug(1, "SUCCESS continuing PBX on chan %s\n", ast_channel_name(final_dest_chan));
}
} else {
- ast_hangup(final_dest_chan);
+ ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
}
} else {
ast_debug(1, "chan %s was hungup\n", ast_channel_name(final_dest_chan));
- ast_hangup(final_dest_chan);
+ ast_autoservice_chan_hangup_peer(chan, final_dest_chan);
}
done:
ast_free((char *) bconfig.warning_sound);