diff options
-rwxr-xr-x | configs/extensions.conf.sample | 20 | ||||
-rwxr-xr-x | include/asterisk/pbx.h | 5 | ||||
-rwxr-xr-x | pbx.c | 155 | ||||
-rwxr-xr-x | pbx/pbx_config.c | 7 |
4 files changed, 125 insertions, 62 deletions
diff --git a/configs/extensions.conf.sample b/configs/extensions.conf.sample index 0fca00134..8e925be55 100755 --- a/configs/extensions.conf.sample +++ b/configs/extensions.conf.sample @@ -21,6 +21,16 @@ static=yes ; CLI command 'save dialplan' too ; 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 ';') ; 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 ; exten => _9011.,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) -exten => _9011.,n,Congestion [trunkld] ; ; Long distance context accessed through trunk ; exten => _91NXXNXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) -exten => _91NXXNXXXXXX,n,Congestion [trunklocal] ; ; Local seven-digit dialing accessed through trunk interface ; exten => _9NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) -exten => _9NXXXXXX,n,Congestion [trunktollfree] ; ; Long distance context accessed through trunk interface ; exten => _91800NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) -exten => _91800NXXXXXX,n,Congestion exten => _91888NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) -exten => _91888NXXXXXX,n,Congestion exten => _91877NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) -exten => _91877NXXXXXX,n,Congestion exten => _91866NXXXXXX,1,Dial(${TRUNK}/${EXTEN:${TRUNKMSD}}) -exten => _91866NXXXXXX,n,Congestion [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(restart),BackGround(demo-congrats) ; Play a congratulatory message 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,n,Goto(s,instruct) @@ -281,6 +285,7 @@ exten => 8500,n,Goto(s,6) ; ;exten => s,1,Answer ;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 => 2,1,Hangup ;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,n,Wait,2 ;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 => 2,1,Goto(default,mark,2) diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index bea2efb28..1a8b7e502 100755 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -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); +/* 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) } #endif @@ -177,6 +177,8 @@ char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name); static struct varshead globals; +static int autofallthrough = 0; + static struct pbx_builtin { char name[AST_MAX_APP]; int (*execute)(struct ast_channel *chan, void *data); @@ -408,9 +410,10 @@ static struct pbx_builtin { { "WaitExten", pbx_builtin_waitexten, "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" - "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; } else { /* Done, wait for an extension */ + waittime = 0; if (digit) waittime = c->pbx->dtimeout; - else + else if (!autofallthrough) waittime = c->pbx->rtimeout; - while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) { - /* As long as we're willing to wait, and as long as it's not defined, - keep reading digits until we can't possibly get a right answer anymore. */ - digit = ast_waitfordigit(c, waittime * 1000); - 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 { - /* 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; + if (waittime) { + while (ast_matchmore_extension(c, c->context, exten, 1, c->cid.cid_num)) { + /* As long as we're willing to wait, and as long as it's not defined, + keep reading digits until we can't possibly get a right answer anymore. */ + digit = ast_waitfordigit(c, waittime * 1000); + if (c->_softhangup == AST_SOFTHANGUP_ASYNCGOTO) { + c->_softhangup = 0; } else { - ast_log(LOG_WARNING, "Invalid extension '%s', but no rule 'i' in context '%s'\n", exten, c->context); - goto out; + 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 { - /* 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; + /* 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 { - ast_log(LOG_WARNING, "Timeout, but no rule 't' in context '%s'\n", c->context); - goto out; - } - } + /* 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 (c->cdr) { - if (option_verbose > 2) - ast_verbose(VERBOSE_PREFIX_2 "CDR updated on %s\n",c->name); - ast_cdr_update(c); - } } } if (firstpass) @@ -2045,6 +2067,15 @@ int ast_pbx_start(struct ast_channel *c) 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 * 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) { int ms; - + int res; /* Wait for "n" seconds */ - if (data && atof((char *)data)) { + if (data && atof((char *)data)) 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) diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c index 0df07bd47..7e0d6d9cd 100755 --- a/pbx/pbx_config.c +++ b/pbx/pbx_config.c @@ -42,6 +42,7 @@ static char *registrar = "pbx_config"; static int static_config = 0; static int write_protect_config = 1; +static int autofallthrough_config = 0; AST_MUTEX_DEFINE_STATIC(save_dialplan_lock); @@ -1629,6 +1630,10 @@ static int pbx_load_module(void) "static")); write_protect_config = ast_true(ast_variable_retrieve(cfg, "general", "writeprotect")); + + autofallthrough_config = ast_true(ast_variable_retrieve(cfg, "general", + "autofallthrough")); + v = ast_variable_browse(cfg, "globals"); while(v) { 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)) ast_context_verify_includes(con); + pbx_set_autofallthrough(autofallthrough_config); + return 0; } |