diff --git a/CHANGES b/CHANGES index 19946ab9d4..140b725811 100644 --- a/CHANGES +++ b/CHANGES @@ -339,6 +339,10 @@ AGI (Asterisk Gateway Interface) will start the playback of the audio at the position specified. It will also return the final position of the file in 'endpos'. + * The SAY ALPHA command now accepts an additional parameter to control + whether it specifies the case of uppercase, lowercase, or all letters to + provide functionality similar to SayAlphaCase. + CDR (Call Detail Records) ------------------ * Significant changes have been made to the behavior of CDRs. For a full diff --git a/apps/app_chanspy.c b/apps/app_chanspy.c index 0f40e31936..061fa261d6 100644 --- a/apps/app_chanspy.c +++ b/apps/app_chanspy.c @@ -1048,7 +1048,7 @@ static int common_exec(struct ast_channel *chan, struct ast_flags *flags, break; } } else { - res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan)); + res = ast_say_character_str(chan, peer_name, "", ast_channel_language(chan), AST_SAY_CASE_NONE); } } if (ptr && (num = atoi(ptr))) { diff --git a/apps/app_directory.c b/apps/app_directory.c index edfc349ea7..ccdac427b4 100644 --- a/apps/app_directory.c +++ b/apps/app_directory.c @@ -281,13 +281,13 @@ static int play_mailbox_owner(struct ast_channel *chan, const char *context, /* If Option 'e' was specified, also read the extension number with the name */ if (ast_test_flag(flags, OPT_SAYEXTENSION)) { ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY); - res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan)); + res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE); } } else { - res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, ast_channel_language(chan)); + res = ast_say_character_str(chan, S_OR(name, ext), AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE); if (!ast_strlen_zero(name) && ast_test_flag(flags, OPT_SAYEXTENSION)) { ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY); - res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan)); + res = ast_say_character_str(chan, ext, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE); } } diff --git a/apps/app_voicemail.c b/apps/app_voicemail.c index 1f048a2836..13e94a8bae 100644 --- a/apps/app_voicemail.c +++ b/apps/app_voicemail.c @@ -13683,7 +13683,7 @@ static int vmsayname_exec(struct ast_channel *chan, const char *data) ast_debug(3, "Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context); res = ast_stream_and_wait(chan, "vm-extension", AST_DIGIT_ANY); if (!res) { - res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, ast_channel_language(chan)); + res = ast_say_character_str(chan, args_copy, AST_DIGIT_ANY, ast_channel_language(chan), AST_SAY_CASE_NONE); } } diff --git a/include/asterisk/say.h b/include/asterisk/say.h index fac606aa81..93c525dd21 100644 --- a/include/asterisk/say.h +++ b/include/asterisk/say.h @@ -148,13 +148,23 @@ SAY_EXTERN int (* ast_say_digit_str_full)(struct ast_channel *chan, const char * */ SAY_EXTERN int (* ast_say_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, const char *options, int audiofd, int ctrlfd) SAY_INIT(ast_say_full); +/*! + * \brief Controls how ast_say_character_str denotes the case of characters in a string + */ +enum ast_say_case_sensitivity { + AST_SAY_CASE_NONE, /*!< Do not distinguish case on any letters */ + AST_SAY_CASE_LOWER, /*!< Denote case only on lower case letters, upper case is assumed otherwise */ + AST_SAY_CASE_UPPER, /*!< Denote case only on upper case letters, lower case is assumed otherwise */ + AST_SAY_CASE_ALL, /*!< Denote case on all letters, upper and lower */ +}; + /*! \brief * function to pronounce character and phonetic strings */ int ast_say_character_str(struct ast_channel *chan, const char *num, - const char *ints, const char *lang); + const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity); -SAY_EXTERN int (* ast_say_character_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, int audiofd, int ctrlfd) SAY_INIT(ast_say_character_str_full); +SAY_EXTERN int (* ast_say_character_str_full)(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity, int audiofd, int ctrlfd) SAY_INIT(ast_say_character_str_full); int ast_say_phonetic_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang); diff --git a/main/channel.c b/main/channel.c index c5ff77b86d..5daf5825e8 100644 --- a/main/channel.c +++ b/main/channel.c @@ -7792,9 +7792,9 @@ int ast_say_digit_str(struct ast_channel *chan, const char *str, } int ast_say_character_str(struct ast_channel *chan, const char *str, - const char *ints, const char *lang) + const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity) { - return ast_say_character_str_full(chan, str, ints, lang, -1, -1); + return ast_say_character_str_full(chan, str, ints, lang, sensitivity, -1, -1); } int ast_say_phonetic_str(struct ast_channel *chan, const char *str, diff --git a/main/pbx.c b/main/pbx.c index d5a46a5fde..27a586ef91 100644 --- a/main/pbx.c +++ b/main/pbx.c @@ -501,6 +501,46 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") CHANNEL + + + Say Alpha. + + + + + + Case sensitive (all) pronunciation. + (Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c). + + + Case sensitive (lower) pronunciation. + (Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c). + + + Case insensitive pronunciation. Equivalent to SayAlpha. + (Ex: SayAlphaCase(n,aBc) - a b c). + + + Case sensitive (upper) pronunciation. + (Ex: SayAlphaCase(u,aBc); - a uppercase b c). + + + + + + + This application will play the sounds that correspond to the letters of the + given string. Optionally, a casetype may be + specified. This will be used for case-insensitive or case-sensitive pronunciations. + + + SayDigits + SayNumber + SayPhonetic + SayAlpha + CHANNEL + + Say Digits. @@ -1122,6 +1162,7 @@ static int pbx_builtin_execiftime(struct ast_channel *, const char *); static int pbx_builtin_saynumber(struct ast_channel *, const char *); static int pbx_builtin_saydigits(struct ast_channel *, const char *); static int pbx_builtin_saycharacters(struct ast_channel *, const char *); +static int pbx_builtin_saycharacters_case(struct ast_channel *, const char *); static int pbx_builtin_sayphonetic(struct ast_channel *, const char *); static int matchcid(const char *cidpattern, const char *callerid); #ifdef NEED_DEBUG @@ -1297,6 +1338,7 @@ static struct pbx_builtin { { "RaiseException", pbx_builtin_raise_exception }, { "Ringing", pbx_builtin_ringing }, { "SayAlpha", pbx_builtin_saycharacters }, + { "SayAlphaCase", pbx_builtin_saycharacters_case }, { "SayDigits", pbx_builtin_saydigits }, { "SayNumber", pbx_builtin_saynumber }, { "SayPhonetic", pbx_builtin_sayphonetic }, @@ -11260,12 +11302,60 @@ static int pbx_builtin_saydigits(struct ast_channel *chan, const char *data) return res; } +static int pbx_builtin_saycharacters_case(struct ast_channel *chan, const char *data) +{ + int res = 0; + int sensitivity = 0; + char *parse; + AST_DECLARE_APP_ARGS(args, + AST_APP_ARG(options); + AST_APP_ARG(characters); + ); + + if (ast_strlen_zero(data)) { + ast_log(LOG_WARNING, "SayAlphaCase requires two arguments (options, characters)\n"); + return 0; + } + + parse = ast_strdupa(data); + AST_STANDARD_APP_ARGS(args, parse); + + if (!args.options || strlen(args.options) != 1) { + ast_log(LOG_WARNING, "SayAlphaCase options are mutually exclusive and required\n"); + return 0; + } + + switch (args.options[0]) { + case 'a': + sensitivity = AST_SAY_CASE_ALL; + break; + case 'l': + sensitivity = AST_SAY_CASE_LOWER; + break; + case 'n': + sensitivity = AST_SAY_CASE_NONE; + break; + case 'u': + sensitivity = AST_SAY_CASE_UPPER; + break; + default: + ast_log(LOG_WARNING, "Invalid option: '%s'\n", args.options); + return 0; + } + + res = ast_say_character_str(chan, args.characters, "", ast_channel_language(chan), sensitivity); + + return res; +} + static int pbx_builtin_saycharacters(struct ast_channel *chan, const char *data) { int res = 0; - if (data) - res = ast_say_character_str(chan, data, "", ast_channel_language(chan)); + if (data) { + res = ast_say_character_str(chan, data, "", ast_channel_language(chan), AST_SAY_CASE_NONE); + } + return res; } diff --git a/main/say.c b/main/say.c index 295d4110f4..ed0a7b5241 100644 --- a/main/say.c +++ b/main/say.c @@ -61,13 +61,15 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$") static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang); -static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd) +static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity, int audiofd, int ctrlfd) { const char *fn; char fnbuf[10], asciibuf[20] = "letters/ascii"; char ltr; int num = 0; int res = 0; + int upper = 0; + int lower = 0; while (str[num] && !res) { fn = NULL; @@ -121,9 +123,35 @@ static int say_character_str_full(struct ast_channel *chan, const char *str, con break; default: ltr = str[num]; - if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */ - strcpy(fnbuf, "letters/X"); - fnbuf[8] = ltr; + if ('A' <= ltr && ltr <= 'Z') { + ltr += 'a' - 'A'; /* file names are all lower-case */ + switch (sensitivity) { + case AST_SAY_CASE_UPPER: + case AST_SAY_CASE_ALL: + upper = !upper; + case AST_SAY_CASE_LOWER: + case AST_SAY_CASE_NONE: + break; + } + } else if ('a' <= ltr && ltr <= 'z') { + switch (sensitivity) { + case AST_SAY_CASE_LOWER: + case AST_SAY_CASE_ALL: + lower = !lower; + case AST_SAY_CASE_UPPER: + case AST_SAY_CASE_NONE: + break; + } + } + + if (upper) { + strcpy(fnbuf, "uppercase"); + } else if (lower) { + strcpy(fnbuf, "lowercase"); + } else { + strcpy(fnbuf, "letters/X"); + fnbuf[8] = ltr; + } fn = fnbuf; } if ((fn && ast_fileexists(fn, NULL, lang) > 0) || @@ -137,6 +165,9 @@ static int say_character_str_full(struct ast_channel *chan, const char *str, con } ast_stopstream(chan); } + if (upper || lower) { + continue; + } num++; } diff --git a/res/res_agi.c b/res/res_agi.c index 6619183fc0..74d665bd50 100644 --- a/res/res_agi.c +++ b/res/res_agi.c @@ -2313,11 +2313,37 @@ static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, const static int handle_sayalpha(struct ast_channel *chan, AGI *agi, int argc, const char * const argv[]) { int res; + int sensitivity = AST_SAY_CASE_NONE; - if (argc != 4) + if (argc < 4 || argc > 5) { return RESULT_SHOWUSAGE; + } - res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), agi->audio, agi->ctrl); + if (argc > 4) { + switch (argv[4][0]) { + case 'a': + case 'A': + sensitivity = AST_SAY_CASE_ALL; + break; + case 'l': + case 'L': + sensitivity = AST_SAY_CASE_LOWER; + break; + case 'n': + case 'N': + sensitivity = AST_SAY_CASE_NONE; + break; + case 'u': + case 'U': + sensitivity = AST_SAY_CASE_UPPER; + break; + case '\0': + break; + default: + return RESULT_SHOWUSAGE; + } + } + res = ast_say_character_str_full(chan, argv[2], argv[3], ast_channel_language(chan), sensitivity, agi->audio, agi->ctrl); if (res == 1) /* New command */ return RESULT_SUCCESS; ast_agi_send(agi->fd, chan, "200 result=%d\n", res);