|
|
|
@ -3170,7 +3170,8 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len
|
|
|
|
|
ast_channel_lock(chan);
|
|
|
|
|
xfer_cfg = ast_get_chan_features_xfer_config(chan);
|
|
|
|
|
if (!xfer_cfg) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to get transfer configuration\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to get transfer configuration\n",
|
|
|
|
|
ast_channel_name(chan));
|
|
|
|
|
ast_channel_unlock(chan);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
@ -3214,9 +3215,9 @@ static int grab_transfer(struct ast_channel *chan, char *exten, size_t exten_len
|
|
|
|
|
} else if (!res) {
|
|
|
|
|
/* 0 for invalid extension dialed. */
|
|
|
|
|
if (ast_strlen_zero(exten)) {
|
|
|
|
|
ast_debug(1, "%s dialed no digits.\n", ast_channel_name(chan));
|
|
|
|
|
ast_verb(4, "%s dialed no digits.\n", ast_channel_name(chan));
|
|
|
|
|
} else {
|
|
|
|
|
ast_debug(1, "%s dialed '%s@%s' does not exist.\n",
|
|
|
|
|
ast_verb(4, "%s dialed '%s@%s' does not exist.\n",
|
|
|
|
|
ast_channel_name(chan), exten, context);
|
|
|
|
|
}
|
|
|
|
|
if (attempts < max_attempts) {
|
|
|
|
@ -3304,8 +3305,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
bridge = ast_bridge_channel_merge_inhibit(bridge_channel, +1);
|
|
|
|
|
|
|
|
|
|
if (strcmp(bridge->v_table->name, "basic")) {
|
|
|
|
|
ast_log(LOG_ERROR, "Attended transfer attempted on unsupported bridge type '%s'.\n",
|
|
|
|
|
bridge->v_table->name);
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Attended transfer attempted on unsupported bridge type '%s'.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan), bridge->v_table->name);
|
|
|
|
|
ast_bridge_merge_inhibit(bridge, -1);
|
|
|
|
|
ao2_ref(bridge, -1);
|
|
|
|
|
return 0;
|
|
|
|
@ -3327,7 +3328,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
props = attended_transfer_properties_alloc(bridge_channel->chan,
|
|
|
|
|
attended_transfer ? attended_transfer->context : NULL);
|
|
|
|
|
if (!props) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to allocate control structure for performing attended transfer.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to allocate control structure for performing attended transfer.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
ast_bridge_merge_inhibit(bridge, -1);
|
|
|
|
|
ao2_ref(bridge, -1);
|
|
|
|
|
return 0;
|
|
|
|
@ -3336,7 +3338,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
props->transferee_bridge = bridge;
|
|
|
|
|
|
|
|
|
|
if (add_transferer_role(props->transferer, attended_transfer)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to set transferrer bridge role.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to set transferrer bridge role.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
attended_transfer_properties_shutdown(props);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
@ -3345,7 +3348,15 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
|
|
|
|
|
/* Grab the extension to transfer to */
|
|
|
|
|
if (grab_transfer(bridge_channel->chan, exten, sizeof(exten), props->context)) {
|
|
|
|
|
ast_log(LOG_WARNING, "Unable to acquire target extension for attended transfer.\n");
|
|
|
|
|
/*
|
|
|
|
|
* XXX The warning here really should be removed. While the
|
|
|
|
|
* message is accurate, this is a normal exit for when the user
|
|
|
|
|
* fails to specify a valid transfer target. e.g., The user
|
|
|
|
|
* hungup, didn't dial any digits, or dialed an invalid
|
|
|
|
|
* extension.
|
|
|
|
|
*/
|
|
|
|
|
ast_log(LOG_WARNING, "Channel %s: Unable to acquire target extension for attended transfer.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
ast_bridge_channel_write_unhold(bridge_channel);
|
|
|
|
|
attended_transfer_properties_shutdown(props);
|
|
|
|
|
return 0;
|
|
|
|
@ -3356,12 +3367,14 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
/* Fill the variable with the extension and context we want to call */
|
|
|
|
|
snprintf(destination, sizeof(destination), "%s@%s", props->exten, props->context);
|
|
|
|
|
|
|
|
|
|
ast_debug(1, "Attended transfer to '%s'\n", destination);
|
|
|
|
|
ast_debug(1, "Channel %s: Attended transfer target '%s'\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan), destination);
|
|
|
|
|
|
|
|
|
|
/* Get a channel that is the destination we wish to call */
|
|
|
|
|
props->transfer_target = dial_transfer(bridge_channel->chan, destination);
|
|
|
|
|
if (!props->transfer_target) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to request outbound channel for attended transfer target.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to request outbound channel for attended transfer target.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
stream_failsound(props->transferer);
|
|
|
|
|
ast_bridge_channel_write_unhold(bridge_channel);
|
|
|
|
|
attended_transfer_properties_shutdown(props);
|
|
|
|
@ -3372,7 +3385,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
/* Create a bridge to use to talk to the person we are calling */
|
|
|
|
|
props->target_bridge = ast_bridge_basic_new();
|
|
|
|
|
if (!props->target_bridge) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to create bridge for attended transfer target.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to create bridge for attended transfer target.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
stream_failsound(props->transferer);
|
|
|
|
|
ast_bridge_channel_write_unhold(bridge_channel);
|
|
|
|
|
ast_hangup(props->transfer_target);
|
|
|
|
@ -3383,7 +3397,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
ast_bridge_merge_inhibit(props->target_bridge, +1);
|
|
|
|
|
|
|
|
|
|
if (attach_framehook(props, props->transfer_target)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to attach framehook to transfer target.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to attach framehook to transfer target.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
stream_failsound(props->transferer);
|
|
|
|
|
ast_bridge_channel_write_unhold(bridge_channel);
|
|
|
|
|
ast_hangup(props->transfer_target);
|
|
|
|
@ -3398,7 +3413,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
BRIDGE_BASIC_PERSONALITY_ATXFER, props);
|
|
|
|
|
|
|
|
|
|
if (ast_call(props->transfer_target, destination, 0)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to place outbound call to transfer target.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to place outbound call to transfer target.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
stream_failsound(props->transferer);
|
|
|
|
|
ast_bridge_channel_write_unhold(bridge_channel);
|
|
|
|
|
ast_hangup(props->transfer_target);
|
|
|
|
@ -3414,7 +3430,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
ast_channel_ref(props->transfer_target);
|
|
|
|
|
if (ast_bridge_impart(props->target_bridge, props->transfer_target, NULL, NULL,
|
|
|
|
|
AST_BRIDGE_IMPART_CHAN_INDEPENDENT)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to place transfer target into bridge.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to place transfer target into bridge.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
stream_failsound(props->transferer);
|
|
|
|
|
ast_bridge_channel_write_unhold(bridge_channel);
|
|
|
|
|
ast_hangup(props->transfer_target);
|
|
|
|
@ -3424,7 +3441,8 @@ static int feature_attended_transfer(struct ast_bridge_channel *bridge_channel,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ast_pthread_create_detached(&thread, NULL, attended_transfer_monitor_thread, props)) {
|
|
|
|
|
ast_log(LOG_ERROR, "Unable to create monitoring thread for attended transfer.\n");
|
|
|
|
|
ast_log(LOG_ERROR, "Channel %s: Unable to create monitoring thread for attended transfer.\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan));
|
|
|
|
|
stream_failsound(props->transferer);
|
|
|
|
|
ast_bridge_channel_write_unhold(bridge_channel);
|
|
|
|
|
attended_transfer_properties_shutdown(props);
|
|
|
|
@ -3470,13 +3488,16 @@ static int feature_blind_transfer(struct ast_bridge_channel *bridge_channel, voi
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ast_debug(1, "Channel %s: Blind transfer target '%s@%s'\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan), xfer_exten, xfer_context);
|
|
|
|
|
|
|
|
|
|
if (!ast_strlen_zero(goto_on_blindxfr)) {
|
|
|
|
|
const char *chan_context;
|
|
|
|
|
const char *chan_exten;
|
|
|
|
|
int chan_priority;
|
|
|
|
|
|
|
|
|
|
ast_debug(1, "After transfer, transferer %s goes to %s\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
|
|
|
|
|
ast_debug(1, "After transfer, transferrer %s goes to %s\n",
|
|
|
|
|
ast_channel_name(bridge_channel->chan), goto_on_blindxfr);
|
|
|
|
|
|
|
|
|
|
ast_channel_lock(bridge_channel->chan);
|
|
|
|
|
chan_context = ast_strdupa(ast_channel_context(bridge_channel->chan));
|
|
|
|
|