[svn-commits] russell: branch russell/issue_8413 r62542 - in
/team/russell/issue_8413: conf...
svn-commits at lists.digium.com
svn-commits at lists.digium.com
Tue May 1 12:08:50 MST 2007
Author: russell
Date: Tue May 1 14:08:50 2007
New Revision: 62542
URL: http://svn.digium.com/view/asterisk?view=rev&rev=62542
Log:
Add current patch from 8413
Modified:
team/russell/issue_8413/configs/features.conf.sample
team/russell/issue_8413/res/res_features.c
Modified: team/russell/issue_8413/configs/features.conf.sample
URL: http://svn.digium.com/view/asterisk/team/russell/issue_8413/configs/features.conf.sample?view=diff&rev=62542&r1=62541&r2=62542
==============================================================================
--- team/russell/issue_8413/configs/features.conf.sample (original)
+++ team/russell/issue_8413/configs/features.conf.sample Tue May 1 14:08:50 2007
@@ -34,6 +34,8 @@
;featuredigittimeout = 500 ; Max time (ms) between digits for
; feature activation (default is 500 ms)
;atxfernoanswertimeout = 15 ; Timeout for answer on attended transfer default is 15 seconds.
+;atxferdropcall = false ; Drop call after failed callback, by default system will try to transfer again.
+;atxferloopdelay = 10 ; Number of seconds to sleep between loops (if atxferdropcall = false)
[featuremap]
;blindxfer => #1 ; Blind transfer (default is #)
Modified: team/russell/issue_8413/res/res_features.c
URL: http://svn.digium.com/view/asterisk/team/russell/issue_8413/res/res_features.c?view=diff&rev=62542&r1=62541&r2=62542
==============================================================================
--- team/russell/issue_8413/res/res_features.c (original)
+++ team/russell/issue_8413/res/res_features.c Tue May 1 14:08:50 2007
@@ -104,6 +104,8 @@
static int comebacktoorigin = 1;
static int atxfernoanswertimeout;
+static int atxferdropcall;
+static int atxferloopdelay;
static char *registrar = "res_features"; /*!< Registrar for operations */
@@ -219,7 +221,7 @@
}
}
-static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name);
+static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate);
static void *ast_bridge_call_thread(void *data)
@@ -770,6 +772,7 @@
struct ast_channel *transferee;
const char *transferer_real_context;
char xferto[256] = "";
+ char callbackto[256] = "";
int res;
int outstate=0;
struct ast_channel *newchan;
@@ -821,82 +824,177 @@
l = strlen(xferto);
snprintf(xferto + l, sizeof(xferto) - l, "@%s/n", transferer_real_context); /* append context */
- newchan = ast_feature_request_and_dial(transferer, "Local", ast_best_codec(transferer->nativeformats),
- xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name);
- ast_indicate(transferer, -1);
- if (!newchan) {
+ newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
+ xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1);
+
+
+ if (!ast_check_hangup(transferer)) {
+ /* Transferer is up - old behaviour */
+ ast_indicate(transferer, -1);
+ if (!newchan) {
+ finishup(transferee);
+ /* any reason besides user requested cancel and busy triggers the failed sound */
+ if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
+ ast_stream_and_wait(transferer, xferfailsound, ""))
+ return -1;
+ if (ast_stream_and_wait(transferer, xfersound, ""))
+ ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+ return FEATURE_RETURN_SUCCESS;
+ }
+
+ if (check_compat(transferer, newchan))
+ return -1;
+ memset(&bconfig,0,sizeof(struct ast_bridge_config));
+ ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
+ ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
+ res = ast_bridge_call(transferer, newchan, &bconfig);
+ if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
+ ast_hangup(newchan);
+ if (ast_stream_and_wait(transferer, xfersound, ""))
+ ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+ finishup(transferee);
+ transferer->_softhangup = 0;
+ return FEATURE_RETURN_SUCCESS;
+ }
+ if (check_compat(transferee, newchan))
+ return -1;
+ ast_indicate(transferee, AST_CONTROL_UNHOLD);
+
+ if ((ast_autoservice_stop(transferee) < 0)
+ || (ast_waitfordigit(transferee, 100) < 0)
+ || (ast_waitfordigit(newchan, 100) < 0)
+ || ast_check_hangup(transferee)
+ || ast_check_hangup(newchan)) {
+ ast_hangup(newchan);
+ return -1;
+ }
+ xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
+ if (!xferchan) {
+ ast_hangup(newchan);
+ return -1;
+ }
+ /* Make formats okay */
+ xferchan->readformat = transferee->readformat;
+ xferchan->writeformat = transferee->writeformat;
+ ast_channel_masquerade(xferchan, transferee);
+ ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
+ xferchan->_state = AST_STATE_UP;
+ ast_clear_flag(xferchan, AST_FLAGS_ALL);
+ xferchan->_softhangup = 0;
+ if ((f = ast_read(xferchan)))
+ ast_frfree(f);
+ newchan->_state = AST_STATE_UP;
+ ast_clear_flag(newchan, AST_FLAGS_ALL);
+ newchan->_softhangup = 0;
+ tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
+ if (!tobj) {
+ ast_hangup(xferchan);
+ ast_hangup(newchan);
+ return -1;
+ }
+ tobj->chan = xferchan;
+ tobj->peer = newchan;
+ tobj->bconfig = *config;
+
+ if (ast_stream_and_wait(newchan, xfersound, ""))
+ ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+ ast_bridge_call_thread_launch(tobj);
+ return -1; /* XXX meaning the channel is bridged ? */
+ } else if(!ast_check_hangup(transferee)) {
+ /* act as blind transfer */
+ if (ast_autoservice_stop(transferee) < 0) {
+ ast_hangup(newchan);
+ return -1;
+ }
+
+ if (!newchan) {
+ /* newchan wasn't created - we should callback to transferer */
+ if (!ast_exists_extension(transferer, transferer_real_context, transferer->cid.cid_num, 1, transferee->cid.cid_num)) {
+ ast_log(LOG_WARNING, "Extension %s does not exist in context %s - callback failed\n",transferer->cid.cid_num,transferer_real_context);
+ if (ast_stream_and_wait(transferee, "beeperr", ""))
+ return -1;
+ return FEATURE_RETURN_SUCCESS;
+ }
+ snprintf(callbackto, sizeof(callbackto), "%s@%s/n", transferer->cid.cid_num, transferer_real_context); /* append context */
+
+ newchan = ast_feature_request_and_dial(transferee, NULL, "Local", ast_best_codec(transferee->nativeformats),
+ callbackto, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0);
+ while (!newchan && !atxferdropcall) {
+ /* Trying to transfer again */
+ ast_autoservice_start(transferee);
+ ast_indicate(transferee, AST_CONTROL_HOLD);
+
+ newchan = ast_feature_request_and_dial(transferer, transferee, "Local", ast_best_codec(transferer->nativeformats),
+ xferto, atxfernoanswertimeout, &outstate, transferer->cid.cid_num, transferer->cid.cid_name, 1);
+ if (ast_autoservice_stop(transferee) < 0) {
+ ast_hangup(newchan);
+ return -1;
+ }
+ if (!newchan) {
+ /* Transfer failed, sleeping */
+ ast_log(LOG_DEBUG, "Sleeping for %d ms before callback.\n", atxferloopdelay);
+ ast_safe_sleep(transferee, atxferloopdelay);
+ ast_log(LOG_DEBUG, "Trying to callback...\n");
+ newchan = ast_feature_request_and_dial(transferee, NULL, "Local", ast_best_codec(transferee->nativeformats),
+ callbackto, atxfernoanswertimeout, &outstate, transferee->cid.cid_num, transferee->cid.cid_name, 0);
+ }
+ }
+ }
+ if (!newchan) {
+ return -1;
+ }
+
+ /* newchan is up, we should prepare transferee and bridge them */
+ if (check_compat(transferee, newchan))
+ return -1;
+ ast_indicate(transferee, AST_CONTROL_UNHOLD);
+
+ if ((ast_waitfordigit(transferee, 100) < 0)
+ || (ast_waitfordigit(newchan, 100) < 0)
+ || ast_check_hangup(transferee)
+ || ast_check_hangup(newchan)) {
+ ast_hangup(newchan);
+ return -1;
+ }
+
+ xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
+ if (!xferchan) {
+ ast_hangup(newchan);
+ return -1;
+ }
+ /* Make formats okay */
+ xferchan->readformat = transferee->readformat;
+ xferchan->writeformat = transferee->writeformat;
+ ast_channel_masquerade(xferchan, transferee);
+ ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
+ xferchan->_state = AST_STATE_UP;
+ ast_clear_flag(xferchan, AST_FLAGS_ALL);
+ xferchan->_softhangup = 0;
+ if ((f = ast_read(xferchan)))
+ ast_frfree(f);
+ newchan->_state = AST_STATE_UP;
+ ast_clear_flag(newchan, AST_FLAGS_ALL);
+ newchan->_softhangup = 0;
+ tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
+ if (!tobj) {
+ ast_hangup(xferchan);
+ ast_hangup(newchan);
+ return -1;
+ }
+ tobj->chan = xferchan;
+ tobj->peer = newchan;
+ tobj->bconfig = *config;
+
+ if (ast_stream_and_wait(newchan, xfersound, ""))
+ ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
+ ast_bridge_call_thread_launch(tobj);
+ return -1; /* XXX meaning the channel is bridged ? */
+
+ } else {
+ /* Transferee hanged up */
finishup(transferee);
- /* any reason besides user requested cancel and busy triggers the failed sound */
- if (outstate != AST_CONTROL_UNHOLD && outstate != AST_CONTROL_BUSY &&
- ast_stream_and_wait(transferer, xferfailsound, ""))
- return -1;
- return FEATURE_RETURN_SUCCESS;
- }
-
- if (check_compat(transferer, newchan))
return -1;
- memset(&bconfig,0,sizeof(struct ast_bridge_config));
- ast_set_flag(&(bconfig.features_caller), AST_FEATURE_DISCONNECT);
- ast_set_flag(&(bconfig.features_callee), AST_FEATURE_DISCONNECT);
- res = ast_bridge_call(transferer, newchan, &bconfig);
- if (newchan->_softhangup || newchan->_state != AST_STATE_UP || !transferer->_softhangup) {
- ast_hangup(newchan);
- if (ast_stream_and_wait(transferer, xfersound, ""))
- ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
- finishup(transferee);
- transferer->_softhangup = 0;
- return FEATURE_RETURN_SUCCESS;
- }
-
- if (check_compat(transferee, newchan))
- return -1;
-
- ast_indicate(transferee, AST_CONTROL_UNHOLD);
-
- if ((ast_autoservice_stop(transferee) < 0)
- || (ast_waitfordigit(transferee, 100) < 0)
- || (ast_waitfordigit(newchan, 100) < 0)
- || ast_check_hangup(transferee)
- || ast_check_hangup(newchan)) {
- ast_hangup(newchan);
- return -1;
- }
-
- xferchan = ast_channel_alloc(0, AST_STATE_DOWN, 0, 0, "", "", "", 0, "Transfered/%s", transferee->name);
- if (!xferchan) {
- ast_hangup(newchan);
- return -1;
- }
- /* Make formats okay */
- xferchan->readformat = transferee->readformat;
- xferchan->writeformat = transferee->writeformat;
- ast_channel_masquerade(xferchan, transferee);
- ast_explicit_goto(xferchan, transferee->context, transferee->exten, transferee->priority);
- xferchan->_state = AST_STATE_UP;
- ast_clear_flag(xferchan, AST_FLAGS_ALL);
- xferchan->_softhangup = 0;
-
- if ((f = ast_read(xferchan)))
- ast_frfree(f);
-
- newchan->_state = AST_STATE_UP;
- ast_clear_flag(newchan, AST_FLAGS_ALL);
- newchan->_softhangup = 0;
-
- tobj = ast_calloc(1, sizeof(struct ast_bridge_thread_obj));
- if (!tobj) {
- ast_hangup(xferchan);
- ast_hangup(newchan);
- return -1;
- }
- tobj->chan = xferchan;
- tobj->peer = newchan;
- tobj->bconfig = *config;
-
- if (ast_stream_and_wait(newchan, xfersound, ""))
- ast_log(LOG_WARNING, "Failed to play transfer sound!\n");
- ast_bridge_call_thread_launch(tobj);
- return -1; /* XXX meaning the channel is bridged ? */
+ }
}
@@ -1152,7 +1250,7 @@
}
/*! \todo XXX Check - this is very similar to the code in channel.c */
-static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name)
+static struct ast_channel *ast_feature_request_and_dial(struct ast_channel *caller, struct ast_channel *transferee, const char *type, int format, void *data, int timeout, int *outstate, const char *cid_num, const char *cid_name, int igncallerstate)
{
int state = 0;
int cause = 0;
@@ -1194,7 +1292,7 @@
x = 0;
started = ast_tvnow();
to = timeout;
- while (!ast_check_hangup(caller) && timeout && (chan->_state != AST_STATE_UP)) {
+ while (!((transferee && transferee->_softhangup) && (!igncallerstate && ast_check_hangup(caller))) && timeout && (chan->_state != AST_STATE_UP)) {
struct ast_frame *f = NULL;
monitor_chans[0] = caller;
@@ -1249,31 +1347,34 @@
} else if (caller && (active_channel == caller)) {
f = ast_read(caller);
if (f == NULL) { /*doh! where'd he go?*/
- if (caller->_softhangup && !chan->_softhangup) {
- /* make this a blind transfer */
- ready = 1;
+ if(!igncallerstate) {
+ if (caller->_softhangup && !chan->_softhangup) {
+ /* make this a blind transfer */
+ ready = 1;
+ break;
+ }
+ state = AST_CONTROL_HANGUP;
+ res = 0;
break;
}
- state = AST_CONTROL_HANGUP;
- res = 0;
- break;
- }
+ } else {
- if (f->frametype == AST_FRAME_DTMF) {
- dialed_code[x++] = f->subclass;
- dialed_code[x] = '\0';
- if (strlen(dialed_code) == len) {
- x = 0;
- } else if (x && strncmp(dialed_code, disconnect_code, x)) {
- x = 0;
+ if (f->frametype == AST_FRAME_DTMF) {
+ dialed_code[x++] = f->subclass;
dialed_code[x] = '\0';
- }
- if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
- /* Caller Canceled the call */
- state = AST_CONTROL_UNHOLD;
- ast_frfree(f);
- f = NULL;
- break;
+ if (strlen(dialed_code) == len) {
+ x = 0;
+ } else if (x && strncmp(dialed_code, disconnect_code, x)) {
+ x = 0;
+ dialed_code[x] = '\0';
+ }
+ if (*dialed_code && !strcmp(dialed_code, disconnect_code)) {
+ /* Caller Canceled the call */
+ state = AST_CONTROL_UNHOLD;
+ ast_frfree(f);
+ f = NULL;
+ break;
+ }
}
}
}
@@ -2345,6 +2446,8 @@
transferdigittimeout = DEFAULT_TRANSFER_DIGIT_TIMEOUT;
featuredigittimeout = DEFAULT_FEATURE_DIGIT_TIMEOUT;
atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
+ atxferloopdelay = 10000;
+ atxferdropcall = 0;
cfg = ast_config_load("features.conf");
if (!cfg) {
@@ -2406,6 +2509,16 @@
atxfernoanswertimeout = DEFAULT_NOANSWER_TIMEOUT_ATTENDED_TRANSFER;
} else
atxfernoanswertimeout = atxfernoanswertimeout * 1000;
+ } else if (!strcasecmp(var->name, "atxferloopdelay")) {
+ if ((sscanf(var->value, "%d", &atxferloopdelay) != 1) || (atxferloopdelay < 1)) {
+ ast_log(LOG_WARNING, "%s is not a valid atxferloopdelay\n", var->value);
+ atxferloopdelay = 10000;
+ } else
+ atxferloopdelay = atxferloopdelay * 1000;
+ } else if (!strcasecmp(var->name, "atxferdropcall")) {
+ if (ast_true(var->value)) {
+ atxferdropcall = 1;
+ }
} else if (!strcasecmp(var->name, "courtesytone")) {
ast_copy_string(courtesytone, var->value, sizeof(courtesytone));
} else if (!strcasecmp(var->name, "parkedplay")) {
More information about the svn-commits
mailing list