mirror of
https://github.com/asterisk/asterisk.git
synced 2025-09-04 20:04:50 +00:00
Generic call forward api, ast_call_forward()
The function ast_call_forward() forwards a call to an extension specified in an ast_channel's call_forward string. After an ast_channel is called, if the channel's call_forward string is set this function can be used to forward the call to a new channel and terminate the original one. I have included this api call in both channel.c's ast_request_and_dial() and res_feature.c's feature_request_and_dial(). App_dial and app_queue already contain call forward logic specific for their application and options. (closes issue #13630) Reported by: festr Review: https://reviewboard.asterisk.org/r/271/ git-svn-id: https://origsvn.digium.com/svn/asterisk/branches/1.4@198891 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
@@ -717,6 +717,18 @@ struct ast_channel *ast_request_and_dial(const char *type, int format, void *dat
|
||||
|
||||
struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *reason, const char *cidnum, const char *cidname, struct outgoing_helper *oh);
|
||||
|
||||
/*!
|
||||
* \brief Forwards a call to a new channel specified by the original channel's call_forward str. If possible, the new forwarded channel is created and returned while the original one is terminated.
|
||||
* \param caller in channel that requested orig
|
||||
* \param orig channel being replaced by the call forward channel
|
||||
* \param timeout maximum amount of time to wait for setup of new forward channel
|
||||
* \param format requested channel format
|
||||
* \param oh outgoing helper used with original channel
|
||||
* \param outstate reason why unsuccessful (if uncuccessful)
|
||||
* \return Returns the forwarded call's ast_channel on success or NULL on failure
|
||||
*/
|
||||
struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, int format, struct outgoing_helper *oh, int *outstate);
|
||||
|
||||
/*!\brief Register a channel technology (a new channel driver)
|
||||
* Called by a channel module to register the kind of channels it supports.
|
||||
* \param tech Structure defining channel technology or "type"
|
||||
|
@@ -3027,6 +3027,86 @@ char *ast_channel_reason2str(int reason)
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_cause(int cause, int *outstate)
|
||||
{
|
||||
if (outstate) {
|
||||
/* compute error and return */
|
||||
if (cause == AST_CAUSE_BUSY)
|
||||
*outstate = AST_CONTROL_BUSY;
|
||||
else if (cause == AST_CAUSE_CONGESTION)
|
||||
*outstate = AST_CONTROL_CONGESTION;
|
||||
else
|
||||
*outstate = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct ast_channel *ast_call_forward(struct ast_channel *caller, struct ast_channel *orig, int *timeout, int format, struct outgoing_helper *oh, int *outstate)
|
||||
{
|
||||
char tmpchan[256];
|
||||
struct ast_channel *new = NULL;
|
||||
char *data, *type;
|
||||
int cause = 0;
|
||||
|
||||
/* gather data and request the new forward channel */
|
||||
ast_copy_string(tmpchan, orig->call_forward, sizeof(tmpchan));
|
||||
if ((data = strchr(tmpchan, '/'))) {
|
||||
*data++ = '\0';
|
||||
type = tmpchan;
|
||||
} else {
|
||||
const char *forward_context;
|
||||
ast_channel_lock(orig);
|
||||
forward_context = pbx_builtin_getvar_helper(orig, "FORWARD_CONTEXT");
|
||||
snprintf(tmpchan, sizeof(tmpchan), "%s@%s", orig->call_forward, S_OR(forward_context, orig->context));
|
||||
ast_channel_unlock(orig);
|
||||
data = tmpchan;
|
||||
type = "Local";
|
||||
}
|
||||
if (!(new = ast_request(type, format, data, &cause))) {
|
||||
ast_log(LOG_NOTICE, "Unable to create channel for call forward to '%s/%s' (cause = %d)\n", type, data, cause);
|
||||
handle_cause(cause, outstate);
|
||||
ast_hangup(orig);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Copy/inherit important information into new channel */
|
||||
if (oh) {
|
||||
if (oh->vars) {
|
||||
ast_set_variables(new, oh->vars);
|
||||
}
|
||||
if (!ast_strlen_zero(oh->cid_num) && !ast_strlen_zero(oh->cid_name)) {
|
||||
ast_set_callerid(new, oh->cid_num, oh->cid_name, oh->cid_num);
|
||||
}
|
||||
if (oh->parent_channel) {
|
||||
ast_channel_inherit_variables(oh->parent_channel, new);
|
||||
ast_channel_datastore_inherit(oh->parent_channel, new);
|
||||
}
|
||||
if (oh->account) {
|
||||
ast_cdr_setaccount(new, oh->account);
|
||||
}
|
||||
} else if (caller) { /* no outgoing helper so use caller if avaliable */
|
||||
ast_channel_inherit_variables(caller, new);
|
||||
ast_channel_datastore_inherit(caller, new);
|
||||
}
|
||||
|
||||
ast_channel_lock(orig);
|
||||
ast_string_field_set(new, accountcode, orig->accountcode);
|
||||
if (!ast_strlen_zero(orig->cid.cid_num) && !ast_strlen_zero(new->cid.cid_name)) {
|
||||
ast_set_callerid(new, orig->cid.cid_num, orig->cid.cid_name, orig->cid.cid_num);
|
||||
}
|
||||
ast_channel_unlock(orig);
|
||||
|
||||
/* call new channel */
|
||||
if ((*timeout = ast_call(new, data, 0))) {
|
||||
ast_log(LOG_NOTICE, "Unable to call forward to channel %s/%s\n", type, (char *)data);
|
||||
ast_hangup(orig);
|
||||
ast_hangup(new);
|
||||
return NULL;
|
||||
}
|
||||
ast_hangup(orig);
|
||||
|
||||
return new;
|
||||
}
|
||||
|
||||
struct ast_channel *__ast_request_and_dial(const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, struct outgoing_helper *oh)
|
||||
{
|
||||
int dummy_outstate;
|
||||
@@ -3043,11 +3123,7 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
|
||||
chan = ast_request(type, format, data, &cause);
|
||||
if (!chan) {
|
||||
ast_log(LOG_NOTICE, "Unable to request channel %s/%s\n", type, (char *)data);
|
||||
/* compute error and return */
|
||||
if (cause == AST_CAUSE_BUSY)
|
||||
*outstate = AST_CONTROL_BUSY;
|
||||
else if (cause == AST_CAUSE_CONGESTION)
|
||||
*outstate = AST_CONTROL_CONGESTION;
|
||||
handle_cause(cause, outstate);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@@ -3076,6 +3152,13 @@ struct ast_channel *__ast_request_and_dial(const char *type, int format, void *d
|
||||
break;
|
||||
if (timeout > -1)
|
||||
timeout = res;
|
||||
if (!ast_strlen_zero(chan->call_forward)) {
|
||||
if (!(chan = ast_call_forward(NULL, chan, &timeout, format, oh, outstate))) {
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
f = ast_read(chan);
|
||||
if (!f) {
|
||||
*outstate = AST_CONTROL_HANGUP;
|
||||
|
@@ -1445,7 +1445,13 @@ static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *call
|
||||
if (!active_channel)
|
||||
continue;
|
||||
|
||||
if (chan && (chan == active_channel)){
|
||||
if (chan && (chan == active_channel)) {
|
||||
if (!ast_strlen_zero(chan->call_forward)) {
|
||||
if (!(chan = ast_call_forward(caller, chan, &to, format, NULL, outstate))) {
|
||||
return NULL;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
f = ast_read(chan);
|
||||
if (f == NULL) { /*doh! where'd he go?*/
|
||||
state = AST_CONTROL_HANGUP;
|
||||
|
Reference in New Issue
Block a user