]> git.ipfire.org Git - thirdparty/asterisk.git/commitdiff
Add SayAlphaCase and similar functionality for AGI
authorKinsey Moore <kmoore@digium.com>
Thu, 22 Aug 2013 22:33:48 +0000 (22:33 +0000)
committerKinsey Moore <kmoore@digium.com>
Thu, 22 Aug 2013 22:33:48 +0000 (22:33 +0000)
This adds a new dialplan application, SayAlphaCase, that performs much
the same function as SayAlpha except that it takes additional options
which allow the user to specify whether the case of each letter should
be announced for uppercase, lowercase, or all letters. Similar
functionality has been added to the SAY ALPHA AGI command via an
optional parameter.

Original Patch by: Kevin Scott Adams
Reported by: Kevin Scott Adams
Review: https://reviewboard.asterisk.org/r/2725/
(closes issue ASTERISK-20782)

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@397493 65c4cc65-6c06-0410-ace0-fbb531ad65f3

CHANGES
apps/app_chanspy.c
apps/app_directory.c
apps/app_voicemail.c
include/asterisk/say.h
main/channel.c
main/pbx.c
main/say.c
res/res_agi.c

diff --git a/CHANGES b/CHANGES
index 19946ab9d4a4c067b54241729f263ba9b505626e..140b72581116fe45583851c13ad75b0b446f05e8 100644 (file)
--- 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
index 0f40e319369ed1a1bbd46a50e7225629d9b5fd89..061fa261d63de8edd2d20d78de188ff49f9a1f17 100644 (file)
@@ -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))) {
index edfc349ea7ea6279c628fd13db9fdf129e3f123a..ccdac427b4b3d6acdf98d37e0afadd47518ae727 100644 (file)
@@ -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);
                }
        }
 
index 1f048a283687a15429465cee4e98cdfeab6c0335..13e94a8baeb8ca65490b20e5dfdd470d1f489e6c 100644 (file)
@@ -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);
                }
        }
 
index fac606aa81ec0aad21f69d490e746c371479b9da..93c525dd21c21ac584254b32b6243d7ea56a593a 100644 (file)
@@ -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);
index c5ff77b86d2e21687ff0918c4faec1ace596932f..5daf5825e8ccc4523c8065c934f6f85c4bfb9ec6 100644 (file)
@@ -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,
index d5a46a5fdedfb339a7afa57d3dd572c3f493f06c..27a586ef91001f6fbb034a5a9bb849bd2b450fc7 100644 (file)
@@ -501,6 +501,46 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
                        <ref type="function">CHANNEL</ref>
                </see-also>
        </application>
+       <application name="SayAlphaCase" language="en_US">
+               <synopsis>
+                       Say Alpha.
+               </synopsis>
+               <syntax>
+                       <parameter name="casetype" required="true" >
+                               <enumlist>
+                                       <enum name="a">
+                                               <para>Case sensitive (all) pronunciation.
+                                               (Ex: SayAlphaCase(a,aBc); - lowercase a uppercase b lowercase c).</para>
+                                       </enum>
+                                       <enum name="l">
+                                               <para>Case sensitive (lower) pronunciation.
+                                               (Ex: SayAlphaCase(l,aBc); - lowercase a b lowercase c).</para>
+                                       </enum>
+                                       <enum name="n">
+                                               <para>Case insensitive pronunciation. Equivalent to SayAlpha.
+                                               (Ex: SayAlphaCase(n,aBc) - a b c).</para>
+                                       </enum>
+                                       <enum name="u">
+                                               <para>Case sensitive (upper) pronunciation.
+                                               (Ex: SayAlphaCase(u,aBc); - a uppercase b c).</para>
+                                       </enum>
+                               </enumlist>
+                       </parameter>
+                       <parameter name="string" required="true" />
+               </syntax>
+               <description>
+                       <para>This application will play the sounds that correspond to the letters of the
+                       given <replaceable>string</replaceable>.  Optionally, a <replaceable>casetype</replaceable> may be
+                       specified.  This will be used for case-insensitive or case-sensitive pronunciations.</para>
+               </description>
+               <see-also>
+                       <ref type="application">SayDigits</ref>
+                       <ref type="application">SayNumber</ref>
+                       <ref type="application">SayPhonetic</ref>
+                       <ref type="application">SayAlpha</ref>
+                       <ref type="function">CHANNEL</ref>
+               </see-also>
+       </application>
        <application name="SayDigits" language="en_US">
                <synopsis>
                        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;
 }
 
index 295d4110f4639997620f536edc9069d3e49ed348..ed0a7b52417b6263fb5443ac116f62d0924e88d6 100644 (file)
@@ -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++;
        }
 
index 6619183fc0fae1bbd5cbcab7f0e6c5f73a09d136..74d665bd5018fdb9b1ae2cca5f2043a9d9223672 100644 (file)
@@ -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);