diff options
author | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-06-03 15:24:50 +0000 |
---|---|---|
committer | dvossel <dvossel@f38db490-d61c-443f-a65b-d21fe96a405b> | 2009-06-03 15:24:50 +0000 |
commit | 2899f27af389889b18823324275b861938608a04 (patch) | |
tree | c8822842ac43582e09c396c47a4d59e8405161f7 | |
parent | a40b1f9520cb6d9e30fee952cf16b21556b514c3 (diff) |
Merged revisions 198856 via svnmerge from
https://origsvn.digium.com/svn/asterisk/trunk
........
r198856 | dvossel | 2009-06-02 16:17:49 -0500 (Tue, 02 Jun 2009) | 10 lines
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 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: http://svn.digium.com/svn/asterisk/branches/1.6.2@198886 f38db490-d61c-443f-a65b-d21fe96a405b
-rw-r--r-- | include/asterisk/channel.h | 11 | ||||
-rw-r--r-- | main/channel.c | 98 | ||||
-rw-r--r-- | main/features.c | 6 |
3 files changed, 110 insertions, 5 deletions
diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index b69c9d834..c60225fdc 100644 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -864,6 +864,17 @@ 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 *cid_num, const char *cid_name, 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. diff --git a/main/channel.c b/main/channel.c index aab7134f7..22d62ceab 100644 --- a/main/channel.c +++ b/main/channel.c @@ -3563,6 +3563,91 @@ const 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); + while (ast_channel_trylock(new)) { + CHANNEL_DEADLOCK_AVOIDANCE(orig); + } + ast_copy_flags(new->cdr, orig->cdr, AST_CDR_FLAG_ORIGINATED); + 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(new); + 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; @@ -3579,11 +3664,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; } @@ -3614,6 +3695,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; diff --git a/main/features.c b/main/features.c index 8c4296d31..a01f33afe 100644 --- a/main/features.c +++ b/main/features.c @@ -2206,6 +2206,12 @@ static struct ast_channel *feature_request_and_dial(struct ast_channel *caller, continue; 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; |