mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-30 02:26:23 +00:00
This should fix the behavior of the 'T' dial feature being passed incorrectly to the transferee when builtin_atxfers are used.
Also, doing a builtin_atxfer to parking was broken and is fixed here as well. (closes issue #11898) Reported by: sergee Tested by: otherwiseguy git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@122589 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -789,7 +789,7 @@ static int valid_priv_reply(struct ast_flags *opts, int res)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void set_dial_features(struct ast_flags *opts, struct ast_dial_features *features)
|
static void set_dial_features(struct ast_flags *opts, struct ast_dial_features *features, struct ast_channel *chan)
|
||||||
{
|
{
|
||||||
struct ast_flags perm_opts = {.flags = 0};
|
struct ast_flags perm_opts = {.flags = 0};
|
||||||
|
|
||||||
@@ -800,6 +800,22 @@ static void set_dial_features(struct ast_flags *opts, struct ast_dial_features *
|
|||||||
memset(features->options, 0, sizeof(features->options));
|
memset(features->options, 0, sizeof(features->options));
|
||||||
|
|
||||||
ast_app_options2str(dial_exec_options, &perm_opts, features->options, sizeof(features->options));
|
ast_app_options2str(dial_exec_options, &perm_opts, features->options, sizeof(features->options));
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLEE_TRANSFER))
|
||||||
|
ast_set_flag(&(features->features_callee), AST_FEATURE_REDIRECT);
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLER_TRANSFER))
|
||||||
|
ast_set_flag(&(features->features_caller), AST_FEATURE_REDIRECT);
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLEE_HANGUP))
|
||||||
|
ast_set_flag(&(features->features_callee), AST_FEATURE_DISCONNECT);
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLER_HANGUP))
|
||||||
|
ast_set_flag(&(features->features_caller), AST_FEATURE_DISCONNECT);
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLEE_MONITOR))
|
||||||
|
ast_set_flag(&(features->features_callee), AST_FEATURE_AUTOMON);
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLER_MONITOR))
|
||||||
|
ast_set_flag(&(features->features_caller), AST_FEATURE_AUTOMON);
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLEE_PARK))
|
||||||
|
ast_set_flag(&(features->features_callee), AST_FEATURE_PARKCALL);
|
||||||
|
if (ast_test_flag(&perm_opts, OPT_CALLER_PARK))
|
||||||
|
ast_set_flag(&(features->features_caller), AST_FEATURE_PARKCALL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags, int *continue_exec)
|
static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags *peerflags, int *continue_exec)
|
||||||
@@ -1109,18 +1125,16 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(caller_features = ast_malloc(sizeof(*caller_features)))) {
|
if (!(caller_features = ast_calloc(1, sizeof(*caller_features)))) {
|
||||||
ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n");
|
ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
caller_features->is_caller = 1;
|
|
||||||
set_dial_features(&opts, caller_features);
|
|
||||||
|
|
||||||
ds_caller_features->inheritance = DATASTORE_INHERIT_FOREVER;
|
|
||||||
ds_caller_features->data = caller_features;
|
|
||||||
|
|
||||||
ast_channel_lock(chan);
|
ast_channel_lock(chan);
|
||||||
|
caller_features->is_caller = 1;
|
||||||
|
set_dial_features(&opts, caller_features, chan);
|
||||||
|
ds_caller_features->inheritance = -1;
|
||||||
|
ds_caller_features->data = caller_features;
|
||||||
ast_channel_datastore_add(chan, ds_caller_features);
|
ast_channel_datastore_add(chan, ds_caller_features);
|
||||||
ast_channel_unlock(chan);
|
ast_channel_unlock(chan);
|
||||||
|
|
||||||
@@ -1291,23 +1305,20 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags
|
|||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(callee_features = ast_malloc(sizeof(*callee_features)))) {
|
if (!(callee_features = ast_calloc(1, sizeof(*callee_features)))) {
|
||||||
ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n");
|
ast_log(LOG_WARNING, "Unable to allocate memory for feature flags. Aborting!\n");
|
||||||
ast_free(tmp);
|
ast_free(tmp);
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
callee_features->is_caller = 0;
|
|
||||||
set_dial_features(&opts, callee_features);
|
|
||||||
|
|
||||||
ds_callee_features->inheritance = DATASTORE_INHERIT_FOREVER;
|
|
||||||
ds_callee_features->data = callee_features;
|
|
||||||
|
|
||||||
ast_channel_lock(tmp->chan);
|
ast_channel_lock(tmp->chan);
|
||||||
|
callee_features->is_caller = 0;
|
||||||
|
set_dial_features(&opts, callee_features, tmp->chan);
|
||||||
|
ds_callee_features->inheritance = -1;
|
||||||
|
ds_callee_features->data = callee_features;
|
||||||
ast_channel_datastore_add(tmp->chan, ds_callee_features);
|
ast_channel_datastore_add(tmp->chan, ds_callee_features);
|
||||||
ast_channel_unlock(tmp->chan);
|
ast_channel_unlock(tmp->chan);
|
||||||
|
|
||||||
|
|
||||||
/* Place the call, but don't wait on the answer */
|
/* Place the call, but don't wait on the answer */
|
||||||
res = ast_call(tmp->chan, numsubst, 0);
|
res = ast_call(tmp->chan, numsubst, 0);
|
||||||
|
|
||||||
|
@@ -391,8 +391,30 @@ static int park_call_full(struct ast_channel *chan, struct ast_channel *peer, in
|
|||||||
if (extout)
|
if (extout)
|
||||||
*extout = x;
|
*extout = x;
|
||||||
|
|
||||||
if (peer)
|
if (peer) {
|
||||||
ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
|
/* This is so ugly that it hurts, but implementing get_base_channel() on local channels
|
||||||
|
could have ugly side effects. We could have transferer<->local,1<->local,2<->parking
|
||||||
|
and we need the callback name to be that of transferer. Since local,1/2 have the same
|
||||||
|
name we can be tricky and just grab the bridged channel from the other side of the local
|
||||||
|
*/
|
||||||
|
if (!strcasecmp(peer->tech->type, "Local")) {
|
||||||
|
struct ast_channel *tmpchan, *base_peer;
|
||||||
|
char other_side[AST_CHANNEL_NAME];
|
||||||
|
char *c;
|
||||||
|
ast_copy_string(other_side, peer->name, sizeof(other_side));
|
||||||
|
if ((c = strrchr(other_side, ','))) {
|
||||||
|
*++c = '1';
|
||||||
|
}
|
||||||
|
if ((tmpchan = ast_get_channel_by_name_locked(other_side))) {
|
||||||
|
if ((base_peer = ast_bridged_channel(tmpchan))) {
|
||||||
|
ast_copy_string(pu->peername, base_peer->name, sizeof(pu->peername));
|
||||||
|
}
|
||||||
|
ast_channel_unlock(tmpchan);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ast_copy_string(pu->peername, peer->name, sizeof(pu->peername));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Remember what had been dialed, so that if the parking
|
/* Remember what had been dialed, so that if the parking
|
||||||
expires, we try to come back to the same place */
|
expires, we try to come back to the same place */
|
||||||
@@ -792,6 +814,8 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
|
|||||||
struct ast_bridge_config bconfig;
|
struct ast_bridge_config bconfig;
|
||||||
struct ast_frame *f;
|
struct ast_frame *f;
|
||||||
int l;
|
int l;
|
||||||
|
struct ast_datastore *features_datastore;
|
||||||
|
struct ast_dial_features *dialfeatures = NULL;
|
||||||
|
|
||||||
if (option_debug)
|
if (option_debug)
|
||||||
ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
|
ast_log(LOG_DEBUG, "Executing Attended Transfer %s, %s (sense=%d) \n", chan->name, peer->name, sense);
|
||||||
@@ -834,9 +858,22 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
|
|||||||
}
|
}
|
||||||
|
|
||||||
l = strlen(xferto);
|
l = strlen(xferto);
|
||||||
snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
|
snprintf(xferto + l, sizeof(xferto) - l, "@%s", transferer_real_context); /* append context */
|
||||||
newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
|
newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
|
||||||
xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
|
xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, transferer->language);
|
||||||
|
|
||||||
|
/* If we are the callee and we are being transferred, after the masquerade
|
||||||
|
* caller features will really be the original callee features */
|
||||||
|
ast_channel_lock(transferee);
|
||||||
|
if ((features_datastore = ast_channel_datastore_find(transferee, &dial_features_info, NULL))) {
|
||||||
|
dialfeatures = features_datastore->data;
|
||||||
|
}
|
||||||
|
ast_channel_unlock(transferee);
|
||||||
|
|
||||||
|
if (dialfeatures && !dialfeatures->is_caller) {
|
||||||
|
ast_copy_flags(&(config->features_caller), &(dialfeatures->features_callee), AST_FLAGS_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
ast_indicate(transferer, -1);
|
ast_indicate(transferer, -1);
|
||||||
if (!newchan) {
|
if (!newchan) {
|
||||||
finishup(transferee);
|
finishup(transferee);
|
||||||
@@ -909,6 +946,19 @@ static int builtin_atxfer(struct ast_channel *chan, struct ast_channel *peer, st
|
|||||||
ast_hangup(newchan);
|
ast_hangup(newchan);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* For the case where the transfer target is being connected with the original
|
||||||
|
caller store the target's original features, and apply to the bridge */
|
||||||
|
ast_channel_lock(newchan);
|
||||||
|
if ((features_datastore = ast_channel_datastore_find(newchan, &dial_features_info, NULL))) {
|
||||||
|
dialfeatures = features_datastore->data;
|
||||||
|
}
|
||||||
|
ast_channel_unlock(newchan);
|
||||||
|
|
||||||
|
if (dialfeatures) {
|
||||||
|
ast_copy_flags(&(config->features_callee), &(dialfeatures->features_callee), AST_FLAGS_ALL);
|
||||||
|
}
|
||||||
|
|
||||||
tobj->chan = newchan;
|
tobj->chan = newchan;
|
||||||
tobj->peer = xferchan;
|
tobj->peer = xferchan;
|
||||||
tobj->bconfig = *config;
|
tobj->bconfig = *config;
|
||||||
|
Reference in New Issue
Block a user