From 129f90e3db42f66275432638fefa18bf996aae9b Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Fri, 3 Oct 2025 15:56:06 -0400 Subject: [PATCH] sig_analog: Allow '#' to end the inter-digit timeout when dialing. It is customary to allow # to terminate digit collection immediately when there would normally be a timeout. However, currently, users are forced to wait for the timeout to expire when dialing numbers that are prefixes of other valid matches, and there is no way to end the timeout early. Customarily, # terminates the timeout, but at the moment, this is just rejected unless there happens to be a matching extension ending in #. Allow # to terminate the timeout in cases where there is no dialplan match. This ensures that the dialplan is always respected, but if a valid extension has been dialed that happens to prefix other valid matches, # can be used to dial it immediately. Resolves: #1510 --- channels/sig_analog.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/channels/sig_analog.c b/channels/sig_analog.c index 879007658d..d45644fa1d 100644 --- a/channels/sig_analog.c +++ b/channels/sig_analog.c @@ -2422,6 +2422,7 @@ static void *__analog_ss_thread(void *data) while (len < AST_MAX_EXTENSION-1) { int is_exten_parking = 0; int is_lastnumredial = 0; + int is_endofdialing = 0; /* Read digit unless it's supposed to be immediate, in which case the only answer is 's' */ @@ -2438,8 +2439,27 @@ static void *__analog_ss_thread(void *data) goto quit; } else if (res) { ast_debug(1,"waitfordigit returned '%c' (%d), timeout = %d\n", res, res, timeout); - exten[len++]=res; + exten[len++] = res; exten[len] = '\0'; + if (len > 1 && res == '#' && !ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) { + /* The user was dialing something that matched, but as soon as he dialed #, we no longer have a match. + * Check if what was dialed immediately prior to the # is an extension that exists. + * If so, we can treat "#" as the end of dialing terminator to allow user to complete the call without a timeout. + * This is fully compatible with the user's dialplan, since we only do this if there isn't a dialplan match. */ + exten[--len] = '\0'; /* Remove '#' from the buffer to test the extension without it */ + if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) { + /* The number dialed prior to the # exists as a valid extension. + * Since the number with # does not exist, treat # as end of dialing. */ + ast_debug(1, "Interpreting '#' as end of dialing\n"); + is_endofdialing = 1; + } else { + /* Even without the #, the number in the buffer is not a valid extension. + * In this case, it's still invalid; do nothing special. + * We simply reverse the removal of '#' from the buffer, i.e. we append it again. */ + exten[len++] = res; + exten[len ] = '\0'; + } + } } if (!ast_ignore_pattern(ast_channel_context(chan), exten)) { analog_play_tone(p, idx, -1); @@ -2468,7 +2488,7 @@ static void *__analog_ss_thread(void *data) } } if (ast_exists_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num) && !is_exten_parking) { - if (!res || is_lastnumredial || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) { + if (!res || is_lastnumredial || is_endofdialing || !ast_matchmore_extension(chan, ast_channel_context(chan), exten, 1, p->cid_num)) { if (getforward) { /* Record this as the forwarding extension */ analog_lock_private(p);