dect
/
asterisk
Archived
13
0
Fork 0

Add autofallthrough mode

git-svn-id: http://svn.digium.com/svn/asterisk/trunk@4020 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
markster 2004-10-16 19:46:02 +00:00
parent 0b59f08c8d
commit 5c9fef377d
4 changed files with 127 additions and 64 deletions

View File

@ -21,6 +21,16 @@ static=yes
; CLI command 'save dialplan' too ; CLI command 'save dialplan' too
; ;
writeprotect=no writeprotect=no
;
; If autofallthrough is set, then if an extension runs out of
; things to do, it will terminate the call with BUSY, CONGESTION
; or HANGUP depending on Asterisk's best guess (strongly recommended).
;
; If autofallthrough is not set, then if an extension runs out of
; things to do, asterisk will wait for a new extension to be dialed
; (this is the original behavior of Asterisk 1.0 and earlier).
;
autofallthrough=yes
; You can include other config files, use the #include command (without the ';') ; You can include other config files, use the #include command (without the ';')
; Note that this is different from the "include" command that includes contexts within ; Note that this is different from the "include" command that includes contexts within
@ -121,34 +131,27 @@ exten => _91700XXXXXXX,1,Dial(IAX2/${IAXINFO}@iaxtel.com/${EXTEN:1}@iaxtel)
; International long distance through trunk ; International long distance through trunk
; ;
exten => _9011.,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) exten => _9011.,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}})
exten => _9011.,n,Congestion
[trunkld] [trunkld]
; ;
; Long distance context accessed through trunk ; Long distance context accessed through trunk
; ;
exten => _91NXXNXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) exten => _91NXXNXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}})
exten => _91NXXNXXXXXX,n,Congestion
[trunklocal] [trunklocal]
; ;
; Local seven-digit dialing accessed through trunk interface ; Local seven-digit dialing accessed through trunk interface
; ;
exten => _9NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) exten => _9NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}})
exten => _9NXXXXXX,n,Congestion
[trunktollfree] [trunktollfree]
; ;
; Long distance context accessed through trunk interface ; Long distance context accessed through trunk interface
; ;
exten => _91800NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) exten => _91800NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}})
exten => _91800NXXXXXX,n,Congestion
exten => _91888NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) exten => _91888NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}})
exten => _91888NXXXXXX,n,Congestion
exten => _91877NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) exten => _91877NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}})
exten => _91877NXXXXXX,n,Congestion
exten => _91866NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) exten => _91866NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}})
exten => _91866NXXXXXX,n,Congestion
[international] [international]
; ;
@ -214,6 +217,7 @@ exten => s,n,DigitTimeout,5 ; Set Digit Timeout to 5 seconds
exten => s,n,ResponseTimeout,10 ; Set Response Timeout to 10 seconds exten => s,n,ResponseTimeout,10 ; Set Response Timeout to 10 seconds
exten => s,n(restart),BackGround(demo-congrats) ; Play a congratulatory message exten => s,n(restart),BackGround(demo-congrats) ; Play a congratulatory message
exten => s,n(instruct),BackGround(demo-instruct) ; Play some instructions exten => s,n(instruct),BackGround(demo-instruct) ; Play some instructions
exten => s,n,WaitExten ; Wait for an extension to be dialed.
exten => 2,1,BackGround(demo-moreinfo) ; Give some more information. exten => 2,1,BackGround(demo-moreinfo) ; Give some more information.
exten => 2,n,Goto(s,instruct) exten => 2,n,Goto(s,instruct)
@ -281,6 +285,7 @@ exten => 8500,n,Goto(s,6)
; ;
;exten => s,1,Answer ;exten => s,1,Answer
;exten => s,n,Background(thanks) ; "Thanks for calling press 1 for sales, 2 for support, ..." ;exten => s,n,Background(thanks) ; "Thanks for calling press 1 for sales, 2 for support, ..."
;exten => s,n,WaitExten
;exten => 1,1,Goto(submenu,s,1) ;exten => 1,1,Goto(submenu,s,1)
;exten => 2,1,Hangup ;exten => 2,1,Hangup
;include => default ;include => default
@ -289,6 +294,7 @@ exten => 8500,n,Goto(s,6)
;exten => s,1,Ringing ; Make them comfortable with 2 seconds of ringback ;exten => s,1,Ringing ; Make them comfortable with 2 seconds of ringback
;exten => s,n,Wait,2 ;exten => s,n,Wait,2
;exten => s,n,Background(submenuopts) ; "Thanks for calling the sales department. Press 1 for steve, 2 for..." ;exten => s,n,Background(submenuopts) ; "Thanks for calling the sales department. Press 1 for steve, 2 for..."
;exten => s,n,WaitExten
;exten => 1,1,Goto(default,steve,1) ;exten => 1,1,Goto(default,steve,1)
;exten => 2,1,Goto(default,mark,2) ;exten => 2,1,Goto(default,mark,2)

View File

@ -550,6 +550,11 @@ extern void pbx_substitute_variables_helper(struct ast_channel *c,const char *cp
int ast_extension_patmatch(const char *pattern, const char *data); int ast_extension_patmatch(const char *pattern, const char *data);
/* Set "autofallthrough" flag, if newval is <0, does not acutally set. If
set to 1, sets to auto fall through. If newval set to 0, sets to no auto
fall through (reads extension instead). Returns previous value. */
extern int pbx_set_autofallthrough(int newval);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} }
#endif #endif

159
pbx.c
View File

@ -177,6 +177,8 @@ char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
static struct varshead globals; static struct varshead globals;
static int autofallthrough = 0;
static struct pbx_builtin { static struct pbx_builtin {
char name[AST_MAX_APP]; char name[AST_MAX_APP];
int (*execute)(struct ast_channel *chan, void *data); int (*execute)(struct ast_channel *chan, void *data);
@ -408,9 +410,10 @@ static struct pbx_builtin {
{ "WaitExten", pbx_builtin_waitexten, { "WaitExten", pbx_builtin_waitexten,
"Waits for some time", "Waits for some time",
" Wait(seconds): Waits for the user to enter a new extension for the \n" " Wait([seconds]): Waits for the user to enter a new extension for the \n"
"specified number of seconds, then returns 0. Seconds can be passed with\n" "specified number of seconds, then returns 0. Seconds can be passed with\n"
"fractions of a second. (eg: 1.5 = 1.5 seconds)\n" "fractions of a seconds (eg: 1.5 = 1.5 seconds) or if unspecified the\n"
"default extension timeout will be used.\n"
}, },
}; };
@ -1927,63 +1930,82 @@ int ast_pbx_run(struct ast_channel *c)
c->_softhangup = 0; c->_softhangup = 0;
} else { } else {
/* Done, wait for an extension */ /* Done, wait for an extension */
waittime = 0;
if (digit) if (digit)
waittime = c->pbx->dtimeout; waittime = c->pbx->dtimeout;
else else if (!autofallthrough)
waittime = c->pbx->rtimeout; waittime = c->pbx->rtimeout;
while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) { if (waittime) {
/* As long as we're willing to wait, and as long as it's not defined, while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) {
keep reading digits until we can't possibly get a right answer anymore. */ /* As long as we're willing to wait, and as long as it's not defined,
digit = ast_waitfordigit(c, waittime * 1000); keep reading digits until we can't possibly get a right answer anymore. */
if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) { digit = ast_waitfordigit(c, waittime * 1000);
c->_softhangup = 0; if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) {
c->_softhangup = 0;
} else {
if (!digit)
/* No entry */
break;
if (digit < 0)
/* Error, maybe a hangup */
goto out;
exten[pos++] = digit;
waittime = c->pbx->dtimeout;
}
}
if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
/* Prepare the next cycle */
strncpy(c->exten, exten, sizeof(c->exten)-1);
c->priority = 1;
} else { } else {
if (!digit) /* No such extension */
/* No entry */ if (!ast_strlen_zero(exten)) {
break; /* An invalid extension */
if (digit < 0) if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
/* Error, maybe a hangup */ if (option_verbose > 2)
goto out; ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
exten[pos++] = digit; pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
waittime = c->pbx->dtimeout; strncpy(c->exten, "i", sizeof(c->exten)-1);
c->priority = 1;
} else {
ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
goto out;
}
} else {
/* A simple timeout */
if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
strncpy(c->exten, "t", sizeof(c->exten)-1);
c->priority = 1;
} else {
ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
goto out;
}
}
}
if (c->cdr) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
ast_cdr_update(c);
}
} else {
if (option_verbose > 0) {
char *status;
status = pbx_builtin_getvar_helper(c, "DIALSTATUS");
if (!status)
status = "UNKNOWN";
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "Auto fallthrough, channel '%s' status is '%s'\n", c->name, status);
if (!strcasecmp(status, "CONGESTION"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "CHANUNAVAIL"))
res = pbx_builtin_congestion(c, "10");
else if (!strcasecmp(status, "BUSY"))
res = pbx_builtin_busy(c, "10");
goto out;
} }
} }
if (ast_exists_extension(c, c->context, exten, 1, c->cid.cid_num)) {
/* Prepare the next cycle */
strncpy(c->exten, exten, sizeof(c->exten)-1);
c->priority = 1;
} else {
/* No such extension */
if (!ast_strlen_zero(exten)) {
/* An invalid extension */
if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Invalid extension '%s' in context '%s' on %s\n", exten, c->context, c->name);
pbx_builtin_setvar_helper(c, "INVALID_EXTEN", exten);
strncpy(c->exten, "i", sizeof(c->exten)-1);
c->priority = 1;
} else {
ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context);
goto out;
}
} else {
/* A simple timeout */
if (ast_exists_extension(c, c->context, "t", 1, c->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "Timeout on %s\n", c->name);
strncpy(c->exten, "t", sizeof(c->exten)-1);
c->priority = 1;
} else {
ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context);
goto out;
}
}
}
if (c->cdr) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name);
ast_cdr_update(c);
}
} }
} }
if (firstpass) if (firstpass)
@ -2045,6 +2067,15 @@ int ast_pbx_start(struct ast_channel *c)
return 0; return 0;
} }
int pbx_set_autofallthrough(int newval)
{
int oldval;
oldval = autofallthrough;
if (oldval != newval)
autofallthrough = newval;
return oldval;
}
/* /*
* This function locks contexts list by &conlist, search for the right context * This function locks contexts list by &conlist, search for the right context
* structure, leave context list locked and call ast_context_remove_include2 * structure, leave context list locked and call ast_context_remove_include2
@ -4717,13 +4748,27 @@ static int pbx_builtin_wait(struct ast_channel *chan, void *data)
static int pbx_builtin_waitexten(struct ast_channel *chan, void *data) static int pbx_builtin_waitexten(struct ast_channel *chan, void *data)
{ {
int ms; int ms;
int res;
/* Wait for "n" seconds */ /* Wait for "n" seconds */
if (data && atof((char *)data)) { if (data && atof((char *)data))
ms = atof((char *)data) * 1000; ms = atof((char *)data) * 1000;
return ast_waitfordigit(chan, ms); else if (chan->pbx)
ms = chan->pbx->rtimeout * 1000;
else
ms = 10000;
res = ast_waitfordigit(chan, ms);
if (!res) {
if (ast_exists_extension(chan, chan->context, "t", 1, chan->cid.cid_num)) {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Timeout on %s\n", chan->name);
strncpy(chan->exten, "t", sizeof(chan->exten));
chan->priority = 0;
} else {
ast_log(LOG_WARNING, "Timeout but no rule 't' in context '%s'\n", chan->context);
res = -1;
}
} }
return 0; return res;
} }
static int pbx_builtin_background(struct ast_channel *chan, void *data) static int pbx_builtin_background(struct ast_channel *chan, void *data)

View File

@ -42,6 +42,7 @@ static char *registrar = "pbx_config";
static int static_config = 0; static int static_config = 0;
static int write_protect_config = 1; static int write_protect_config = 1;
static int autofallthrough_config = 0;
AST_MUTEX_DEFINE_STATIC(save_dialplan_lock); AST_MUTEX_DEFINE_STATIC(save_dialplan_lock);
@ -1629,6 +1630,10 @@ static int pbx_load_module(void)
"static")); "static"));
write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", write_protect_config = ast_true(ast_variable_retrieve(cfg, "general",
"writeprotect")); "writeprotect"));
autofallthrough_config = ast_true(ast_variable_retrieve(cfg, "general",
"autofallthrough"));
v = ast_variable_browse(cfg, "globals"); v = ast_variable_browse(cfg, "globals");
while(v) { while(v) {
memset(realvalue, 0, sizeof(realvalue)); memset(realvalue, 0, sizeof(realvalue));
@ -1774,6 +1779,8 @@ static int pbx_load_module(void)
for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con)) for (con = ast_walk_contexts(NULL); con; con = ast_walk_contexts(con))
ast_context_verify_includes(con); ast_context_verify_includes(con);
pbx_set_autofallthrough(autofallthrough_config);
return 0; return 0;
} }