From 3d375accf7efd909be645fc9fd167b067eb24cf5 Mon Sep 17 00:00:00 2001 From: tilghman Date: Mon, 28 Apr 2008 16:37:45 +0000 Subject: [PATCH] Add incomplete matching to PBX code and app_dial (closes issue #12351) Reported by: Corydon76 Patches: 20080402__pbx_incomplete__3.diff.txt uploaded by Corydon76 (license 14) pbx_incomplete_with_timeout.diff uploaded by fabled (license 448) Tested by: Corydon76, fabled git-svn-id: http://svn.digium.com/svn/asterisk/trunk@114773 614ede4d-c843-0410-af14-a771ab80d22e --- apps/app_dial.c | 13 +++++++--- include/asterisk/pbx.h | 1 + main/pbx.c | 66 +++++++++++++++++++++++++++++++++++++++++++------- 3 files changed, 68 insertions(+), 12 deletions(-) diff --git a/apps/app_dial.c b/apps/app_dial.c index 0cc865a1a..5730d99d7 100644 --- a/apps/app_dial.c +++ b/apps/app_dial.c @@ -1619,6 +1619,13 @@ static int dial_exec_full(struct ast_channel *chan, void *data, struct ast_flags } else { /* Nobody answered, next please? */ res = 0; } + + /* SIP, in particular, sends back this error code to indicate an + * overlap dialled number needs more digits. */ + if (chan->hangupcause == AST_CAUSE_INVALID_NUMBER_FORMAT) { + res = AST_PBX_INCOMPLETE; + } + /* almost done, although the 'else' block is 400 lines */ } else { const char *number; @@ -1958,7 +1965,7 @@ out: senddialendevent(chan, pa.status); ast_debug(1, "Exiting with DIALSTATUS=%s.\n", pa.status); - if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_KEEPALIVE)) { + if ((ast_test_flag64(peerflags, OPT_GO_ON)) && !ast_check_hangup(chan) && (res != AST_PBX_KEEPALIVE) && (res != AST_PBX_INCOMPLETE)) { if (calldurationlimit) chan->whentohangup = 0; res = 0; @@ -2059,9 +2066,9 @@ static int retrydial_exec(struct ast_channel *chan, void *data) } } - if (res < 0) + if (res < 0 || res == AST_PBX_INCOMPLETE) { break; - else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */ + } else if (res > 0) { /* Trying to send the call elsewhere (1 digit ext) */ if (onedigit_goto(chan, context, (char) res, 1)) { res = 0; break; diff --git a/include/asterisk/pbx.h b/include/asterisk/pbx.h index fa0ceb0d2..d38325bca 100644 --- a/include/asterisk/pbx.h +++ b/include/asterisk/pbx.h @@ -42,6 +42,7 @@ extern "C" { #define AST_PBX_ERROR 1 /*!< Jump to the 'e' exten */ #define AST_PBX_KEEPALIVE 10 /*!< Destroy the thread, but don't hang up the channel */ #define AST_PBX_NO_HANGUP_PEER 11 +#define AST_PBX_INCOMPLETE 12 /*!< Return to PBX matching, allowing more digits for the extension */ /*! } */ #define PRIORITY_HINT -1 /*!< Special Priority for a hint */ diff --git a/main/pbx.c b/main/pbx.c index fc2bc98ec..92588bd92 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -302,6 +302,7 @@ static int pbx_builtin_hangup(struct ast_channel *, void *); static int pbx_builtin_background(struct ast_channel *, void *); static int pbx_builtin_wait(struct ast_channel *, void *); static int pbx_builtin_waitexten(struct ast_channel *, void *); +static int pbx_builtin_incomplete(struct ast_channel *, void *); static int pbx_builtin_keepalive(struct ast_channel *, void *); static int pbx_builtin_resetcdr(struct ast_channel *, void *); static int pbx_builtin_setamaflags(struct ast_channel *, void *); @@ -579,6 +580,23 @@ static struct pbx_builtin { "value.\n" }, + { "Incomplete", pbx_builtin_incomplete, + "returns AST_PBX_INCOMPLETE value", + " Incomplete([n]): Signals the PBX routines that the previous matched extension\n" + "is incomplete and that further input should be allowed before matching can\n" + "be considered to be complete. Can be used within a pattern match when\n" + "certain criteria warrants a longer match.\n" + " If the 'n' option is specified, then Incomplete will not attempt to answer\n" + "the channel first. Note that most channel types need to be in Answer state\n" + "in order to receive DTMF.\n" + }, + + { "KeepAlive", pbx_builtin_keepalive, + "returns AST_PBX_KEEPALIVE value", + " KeepAlive(): This application is chiefly meant for internal use with Gosubs.\n" + "Please do not run it alone from the dialplan!\n" + }, + { "NoOp", pbx_builtin_noop, "Do Nothing (No Operation)", " NoOp(): This application does nothing. However, it is useful for debugging\n" @@ -696,12 +714,6 @@ static struct pbx_builtin { "See Also: Playback(application), Background(application).\n" }, - { "KeepAlive", pbx_builtin_keepalive, - "returns AST_PBX_KEEPALIVE value", - " KeepAlive(): This application is chiefly meant for internal use with Gosubs.\n" - "Please do not run it alone from the dialplan!\n" - }, - }; static struct ast_context *contexts; @@ -3582,6 +3594,8 @@ static int __ast_pbx_run(struct ast_channel *c) char dst_exten[256]; /* buffer to accumulate digits */ int pos = 0; /* XXX should check bounds */ int digit = 0; + int invalid = 0; + int timeout = 0; /* loop on priorities in this context/exten */ while ( !(res = ast_spawn_extension(c, c->context, c->exten, c->priority, c->cid.cid_num, &found,1))) { @@ -3617,6 +3631,18 @@ static int __ast_pbx_run(struct ast_channel *c) ast_debug(1, "Spawn extension (%s,%s,%d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name); ast_verb(2, "Spawn extension (%s, %s, %d) exited KEEPALIVE on '%s'\n", c->context, c->exten, c->priority, c->name); error = 1; + } else if (res == AST_PBX_INCOMPLETE) { + ast_debug(1, "Spawn extension (%s,%s,%d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name); + ast_verb(2, "Spawn extension (%s, %s, %d) exited INCOMPLETE on '%s'\n", c->context, c->exten, c->priority, c->name); + + /* Don't cycle on incomplete - this will happen if the only extension that matches is our "incomplete" extension */ + if (!ast_matchmore_extension(c, c->context, c->exten, c->priority, c->cid.cid_num)) { + invalid = 1; + } else { + ast_copy_string(dst_exten, c->exten, sizeof(dst_exten)); + digit = 1; + pos = strlen(dst_exten); + } } else { ast_debug(1, "Spawn extension (%s,%s,%d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); ast_verb(2, "Spawn extension (%s, %s, %d) exited non-zero on '%s'\n", c->context, c->exten, c->priority, c->name); @@ -3657,7 +3683,7 @@ static int __ast_pbx_run(struct ast_channel *c) * hangup. We have options, here. We can either catch the failure * and continue, or we can drop out entirely. */ - if (!ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) { + if (invalid || !ast_exists_extension(c, c->context, c->exten, 1, c->cid.cid_num)) { /*!\note * If there is no match at priority 1, it is not a valid extension anymore. * Try to continue at "i" (for invalid) or "e" (for exception) or exit if @@ -3701,11 +3727,13 @@ static int __ast_pbx_run(struct ast_channel *c) if (collect_digits(c, waittime, dst_exten, sizeof(dst_exten), pos)) break; - if (ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */ + if (res == AST_PBX_INCOMPLETE && ast_strlen_zero(&dst_exten[pos])) + timeout = 1; + if (!timeout && ast_exists_extension(c, c->context, dst_exten, 1, c->cid.cid_num)) /* Prepare the next cycle */ set_ext_pri(c, dst_exten, 1); else { /* No such extension */ - if (!ast_strlen_zero(dst_exten)) { + if (!timeout && !ast_strlen_zero(dst_exten)) { /* An invalid extension */ if (ast_exists_extension(c, c->context, "i", 1, c->cid.cid_num)) { ast_verb(3, "Invalid extension '%s' in context '%s' on %s\n", dst_exten, c->context, c->name); @@ -7365,6 +7393,26 @@ static int pbx_builtin_keepalive(struct ast_channel *chan, void *data) return AST_PBX_KEEPALIVE; } +static int pbx_builtin_incomplete(struct ast_channel *chan, void *data) +{ + char *options = data; + int answer = 1; + + /* Some channels can receive DTMF in unanswered state; some cannot */ + if (!ast_strlen_zero(options) && strchr(options, 'n')) { + answer = 0; + } + + /* If the channel is hungup, stop waiting */ + if (ast_check_hangup(chan)) { + return -1; + } else if (chan->_state != AST_STATE_UP && answer) { + __ast_answer(chan, 0); + } + + return AST_PBX_INCOMPLETE; +} + AST_APP_OPTIONS(resetcdr_opts, { AST_APP_OPTION('w', AST_CDR_FLAG_POSTED), AST_APP_OPTION('a', AST_CDR_FLAG_LOCKED), -- 2.11.4.GIT