From 72c6e95ed1e59bf976c23d5267c776cfb92d0b2b Mon Sep 17 00:00:00 2001 From: Naveen Albert Date: Wed, 27 Sep 2023 08:49:07 -0400 Subject: [PATCH] app_directory: Add ADSI support to Directory. This adds optional ADSI support to the Directory application, which allows callers with ADSI CPE to navigate the Directory system significantly faster than is possible using the audio prompts. Callers can see the directory name (and optionally extension) on their screenphone and confirm or reject a match immediately rather than waiting for it to be spelled out, enhancing usability. Resolves: #356 --- apps/app_directory.c | 92 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 91 insertions(+), 1 deletion(-) diff --git a/apps/app_directory.c b/apps/app_directory.c index 40f78966cd..582e1dccb6 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -39,6 +39,7 @@ #include "asterisk/say.h" #include "asterisk/app.h" #include "asterisk/utils.h" +#include "asterisk/adsi.h" /*** DOCUMENTATION @@ -111,12 +112,17 @@ Skip calling the extension, instead set it in the DIRECTORY_EXTEN channel variable. + Only one of the f, l, or b options may be specified. If more than one is specified, then Directory will act as if b was specified. The number of characters for the user to type defaults to 3. - @@ -167,6 +173,7 @@ enum { OPT_ALIAS = (1 << 7), OPT_CONFIG_FILE = (1 << 8), OPT_SKIP = (1 << 9), + OPT_ADSI = (1 << 10), }; enum { @@ -200,8 +207,72 @@ AST_APP_OPTIONS(directory_app_options, { AST_APP_OPTION('a', OPT_ALIAS), AST_APP_OPTION_ARG('c', OPT_CONFIG_FILE, OPT_ARG_FILENAME), AST_APP_OPTION('s', OPT_SKIP), + AST_APP_OPTION('d', OPT_ADSI), /* (Would've used 'a', but that was taken already) */ }); +static int adsi_search_input(struct ast_channel *chan) +{ + unsigned char buf[256]; + int bytes = 0; + unsigned char keys[6]; + + memset(keys, 0, sizeof(keys)); + + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", ""); + bytes += ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", ""); + bytes += ast_adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1); + bytes += ast_adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Query: ***", ""); + bytes += ast_adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Search", "Search", "#", 1); + bytes += ast_adsi_set_keys(buf + bytes, keys); + bytes += ast_adsi_voice_mode(buf + bytes, 0); + + ast_debug(3, "Sending ADSI search input screen on %s\n", ast_channel_name(chan)); + + return ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); +} + +static int adsi_confirm_match(struct ast_channel *chan, int seq, int total, const char *exten, const char *name, int showexten) +{ + unsigned char buf[4096]; + int alignments[5] = {ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT, ADSI_JUST_CENT}; + char *lines[5] = {NULL, NULL, NULL, NULL, NULL}; + int x, bytes = 0; + unsigned char keys[8]; + char matchbuf[32]; + + snprintf(matchbuf, sizeof(matchbuf), "%d of %d", seq + 1, total); /* Make it 1-indexed for user consumption */ + + lines[0] = " "; /* Leave the first line empty so the following lines stand out more */ + lines[1] = matchbuf; + lines[2] = (char*) name; + + if (showexten) { + /* If say extension option is set, show it for ADSI as well */ + lines[3] = (char*) exten; + } + + /* Don't use ast_adsi_print here, this way we can send it all at once instead of in 2 transmissions */ + for (x = 0; lines[x]; x++) { + bytes += ast_adsi_display(buf + bytes, ADSI_INFO_PAGE, x + 1, alignments[x], 0, lines[x], ""); + } + bytes += ast_adsi_set_line(buf + bytes, ADSI_INFO_PAGE, 1); + + keys[3] = ADSI_KEY_APPS + 3; + keys[4] = ADSI_KEY_APPS + 4; + keys[5] = ADSI_KEY_APPS + 5; + /* You might think we only need to set the keys up the first time, but nope, we've got to do it each time. */ + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Dial", "Dial", "1", 0); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Next", "Next", "*", 0); + bytes += ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 0); + bytes += ast_adsi_set_keys(buf + bytes, keys); + bytes += ast_adsi_voice_mode(buf + bytes, 0); + + ast_debug(3, "Sending ADSI confirmation menu for %s\n", name); + + return ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY); +} + static int compare(const char *text, const char *template) { char digit; @@ -376,6 +447,10 @@ static int select_item_seq(struct ast_channel *chan, struct directory_item **ite for (ptr = items, i = 0; i < count; i++, ptr++) { item = *ptr; + if (ast_test_flag(flags, OPT_ADSI) && adsi_confirm_match(chan, i, count, item->exten, item->name, ast_test_flag(flags, OPT_SAYEXTENSION))) { + return -1; + } + for (loop = 3 ; loop > 0; loop--) { if (!res) res = play_mailbox_owner(chan, item->context, item->exten, item->name, flags); @@ -935,6 +1010,18 @@ static int directory_exec(struct ast_channel *chan, const char *data) } digits[7] = digit + '0'; + if (ast_test_flag(&flags, OPT_ADSI)) { + if (!ast_adsi_available(chan)) { + ast_log(LOG_WARNING, "ADSI not available on %s\n", ast_channel_name(chan)); + ast_clear_flag(&flags, OPT_ADSI); + } else { + res = ast_adsi_load_session(chan, NULL, 0, 1); + if (res < 0) { + return res; + } + } + } + if (ast_channel_state(chan) != AST_STATE_UP) { if (!ast_test_flag(&flags, OPT_NOANSWER)) { /* Otherwise answer unless we're supposed to read while on-hook */ @@ -942,6 +1029,9 @@ static int directory_exec(struct ast_channel *chan, const char *data) } } for (;;) { + if (ast_test_flag(&flags, OPT_ADSI) && adsi_search_input(chan)) { + return -1; + } if (!ast_strlen_zero(dirintro) && !res) { res = ast_stream_and_wait(chan, dirintro, AST_DIGIT_ANY); } else if (!res) {