Index: include/asterisk/pbx.h =================================================================== --- include/asterisk/pbx.h (revision 112321) +++ include/asterisk/pbx.h (working copy) @@ -42,6 +42,7 @@ #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 */ Index: main/pbx.c =================================================================== --- main/pbx.c (revision 112321) +++ main/pbx.c (working copy) @@ -302,6 +302,7 @@ 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 @@ "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 @@ "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; @@ -3572,6 +3584,19 @@ 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)) { + pbx_builtin_setvar_helper(c, "INVALID_EXTEN", c->exten); + ast_copy_string(c->exten, "i", sizeof(c->exten)); + } 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); @@ -7313,6 +7338,26 @@ 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),