Index: asterisk/pbx.c
===================================================================
RCS file: /usr/cvsroot/asterisk/pbx.c,v
retrieving revision 1.106
diff -i -u -r1.106 pbx.c
--- asterisk/pbx.c	19 Mar 2004 06:36:25 -0000	1.106
+++ asterisk/pbx.c	21 Mar 2004 04:40:42 -0000
@@ -167,7 +167,8 @@
 static int pbx_builtin_gotoif(struct ast_channel *, void *);
 static int pbx_builtin_gotoiftime(struct ast_channel *, void *);
 static int pbx_builtin_saynumber(struct ast_channel *, void *);
-static int pbx_builtin_saydigits(struct ast_channel *, void *);
+static int pbx_builtin_saycharacters(struct ast_channel *, void *);
+static int pbx_builtin_sayphonetic(struct ast_channel *, void *);
 int pbx_builtin_setvar(struct ast_channel *, void *);
 void pbx_builtin_setvar_helper(struct ast_channel *chan, char *name, char *value);
 char *pbx_builtin_getvar_helper(struct ast_channel *chan, char *name);
@@ -288,10 +289,18 @@
 "Say Number",
 "  SayNumber(digits): Says the passed number\n" },
 
-	{ "SayDigits", pbx_builtin_saydigits,
+	{ "SayDigits", pbx_builtin_saycharacters,
 "Say Digits",
 "  SayDigits(digits): Says the passed digits\n" },
 
+	{ "SayAlpha", pbx_builtin_saycharacters,
+"Say Alpha",
+"  SayAlpha(string): Spells the passed string\n" },
+
+	{ "SayPhonetic", pbx_builtin_sayphonetic,
+"Say Phonetic",
+"  SayPhonetic(string): Spells the passed string with phonetic alphabet\n" },
+
 	{ "SetAccount", pbx_builtin_setaccount,
 "Sets account code",
 "  SetAccount([account]):  Set  the  channel account code for billing\n"
@@ -4556,7 +4565,23 @@
 {
 	int res = 0;
 	if (data)
-		res = ast_say_digit_str(chan, (char *)data, "", chan->language);
+		res = ast_say_character_str(chan, (char *)data, "", chan->language);
+	return res;
+}
+	
+static int pbx_builtin_saycharacters(struct ast_channel *chan, void *data)
+{
+	int res = 0;
+	if (data)
+		res = ast_say_character_str(chan, (char *)data, "", chan->language);
+	return res;
+}
+	
+static int pbx_builtin_sayphonetic(struct ast_channel *chan, void *data)
+{
+	int res = 0;
+	if (data)
+		res = ast_say_phonetic_str(chan, (char *)data, "", chan->language);
 	return res;
 }
 	
Index: asterisk/say.c
===================================================================
RCS file: /usr/cvsroot/asterisk/say.c,v
retrieving revision 1.16
diff -i -u -r1.16 say.c
--- asterisk/say.c	20 Feb 2004 17:43:46 -0000	1.16
+++ asterisk/say.c	21 Mar 2004 04:40:43 -0000
@@ -27,10 +27,11 @@
 
 #define DIGITS_DIR	AST_SOUNDS "/digits/"
 
-int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
+int ast_say_character_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
 {
 	/* XXX Merge with full version? XXX */
 	char fn[256] = "";
+	char ltr;
 	int num = 0;
 	int res = 0;
 	while(fn2[num] && !res) {
@@ -41,8 +42,49 @@
 			case ('#'):
 				snprintf(fn, sizeof(fn), "digits/pound");
 				break;
-			default:
+			case ('0'):
+			case ('1'):
+			case ('2'):
+			case ('3'):
+			case ('4'):
+			case ('5'):
+			case ('6'):
+			case ('7'):
+			case ('8'):
+			case ('9'):
 				snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
+				break;
+			case ('@'):
+				strncpy(fn, "at", sizeof(fn));
+				break;
+			case (','):
+				strncpy(fn, "comma", sizeof(fn));
+				break;
+			case ('-'):
+				strncpy(fn, "dash", sizeof(fn));
+				break;
+			case ('.'):
+				strncpy(fn, "dot", sizeof(fn));
+				break;
+			case ('$'):
+				strncpy(fn, "dollar", sizeof(fn));
+				break;
+			case ('='):
+				strncpy(fn, "equals", sizeof(fn));
+				break;
+			case ('+'):
+				strncpy(fn, "plus", sizeof(fn));
+				break;
+			case ('/'):
+				strncpy(fn, "slash", sizeof(fn));
+				break;
+			case (' '):
+				strncpy(fn, "space", sizeof(fn));
+				break;
+			default:
+				ltr = fn2[num];
+				if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';		/* file names are all lower-case */
+				snprintf(fn, sizeof(fn), "letters/%c", ltr);
 			}
 		res = ast_streamfile(chan, fn, lang);
 		if (!res) 
@@ -53,13 +95,252 @@
 	return res;
 }
 
+/* XXX this should be obsoleted XXX */
+int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
+{
+	return ast_say_character_str(chan, fn2, ints, lang);
+}
+
+int ast_say_phonetic_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
+{
+	/* XXX Merge with full version? XXX */
+	char fn[256] = "";
+	char ltr;
+	int num = 0;
+	int res = 0;
+	int temp;
+	int play;
+	char hex[3];
+/*	while(fn2[num] && !res) { */
+	while(fn2[num]) {
+		play=1;
+		switch (fn2[num]) {
+			case ('*'):
+				snprintf(fn, sizeof(fn), "digits/star");
+				break;
+			case ('#'):
+				snprintf(fn, sizeof(fn), "digits/pound");
+				break;
+			case ('0'):
+			case ('1'):
+			case ('2'):
+			case ('3'):
+			case ('4'):
+			case ('5'):
+			case ('6'):
+			case ('7'):
+			case ('8'):
+				snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
+				break;
+			case ('!'):
+				strncpy(fn, "exclaimation-point", sizeof(fn));
+				break;    	
+			case ('@'):
+				strncpy(fn, "at", sizeof(fn));
+				break;
+			case ('$'):
+				strncpy(fn, "dollar", sizeof(fn));
+				break;	
+			case (','):
+				strncpy(fn, "comma", sizeof(fn));
+				break;
+			case ('-'):
+				strncpy(fn, "dash", sizeof(fn));
+				break;
+			case ('.'):
+				strncpy(fn, "dot", sizeof(fn));
+				break;
+			case ('='):
+				strncpy(fn, "equals", sizeof(fn));
+				break;
+			case ('+'):
+				strncpy(fn, "plus", sizeof(fn));
+				break;
+			case ('/'):
+				strncpy(fn, "slash", sizeof(fn));
+				break;
+			case ('\\'):
+				strncpy(fn, "backslash", sizeof(fn));
+				break;
+			case ('|'):
+				strncpy(fn, "bar", sizeof(fn));
+				break;
+			case (' '):
+				strncpy(fn, "space", sizeof(fn));
+				break;
+			case ('%'):
+				play=0;
+				hex[0]=fn2[num+1];
+				hex[1]=fn2[num+2];
+				hex[2]='\0';
+				if (sscanf(hex,"%x", &temp))
+				{ /* Hex to char convertion successfull */
+				    fn2[num+2]=temp;
+				    num++;
+				    if (temp==37)
+				    { /* If it is a percent, play it now */
+					strncpy(fn, "percent", sizeof(fn));
+					num++;
+					play=1;
+				    }
+				    /* check for invalid characters */
+				    if ((temp<32) || (temp>126))
+				    {
+					num++;
+				    }
+				    				    
+				    
+				}
+				break;
+			default:	/* '9' falls through to here, too */
+				ltr = fn2[num];
+				if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';		/* file names are all lower-case */
+				snprintf(fn, sizeof(fn), "phonetic/%c", ltr);
+			}
+		if (play)
+		{
+		    res = ast_streamfile(chan, fn, lang);
+		    if (!res) 
+			res = ast_waitstream(chan, ints);
+		    ast_stopstream(chan);
+		}
+		num++;
+	}
+	return res;
+}
+
+/* XXX this should be obsoleted XXX */
 int ast_say_digit_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd)
 {
+	return ast_say_character_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
+}
+
+int ast_say_character_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd)
+{
 	char fn[256] = "";
+	char ltr;
 	int num = 0;
 	int res = 0;
 	while(fn2[num] && !res) {
-		snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
+		switch (fn2[num]) {
+			case ('*'):
+				snprintf(fn, sizeof(fn), "digits/star");
+				break;
+			case ('#'):
+				snprintf(fn, sizeof(fn), "digits/pound");
+				break;
+			case ('0'):
+			case ('1'):
+			case ('2'):
+			case ('3'):
+			case ('4'):
+			case ('5'):
+			case ('6'):
+			case ('7'):
+			case ('8'):
+			case ('9'):
+				snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
+				break;
+			case ('@'):
+				strncpy(fn, "at", sizeof(fn));
+				break;
+			case (','):
+				strncpy(fn, "comma", sizeof(fn));
+				break;
+			case ('-'):
+				strncpy(fn, "dash", sizeof(fn));
+				break;
+			case ('.'):
+				strncpy(fn, "dot", sizeof(fn));
+				break;
+			case ('$'):
+				strncpy(fn, "dollar", sizeof(fn));
+				break;
+			case ('='):
+				strncpy(fn, "equals", sizeof(fn));
+				break;
+			case ('+'):
+				strncpy(fn, "plus", sizeof(fn));
+				break;
+			case ('/'):
+				strncpy(fn, "slash", sizeof(fn));
+				break;
+			case (' '):
+				strncpy(fn, "space", sizeof(fn));
+				break;
+			default:
+				ltr = fn2[num];
+				if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';		/* file names are all lower-case */
+				snprintf(fn, sizeof(fn), "letters/%c", ltr);
+			}
+		/* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
+		res = ast_streamfile(chan, fn, lang);
+		if (!res) 
+			res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+		ast_stopstream(chan);
+		num++;
+	}
+	return res;
+}
+
+int ast_say_phonetic_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd)
+{
+	char fn[256] = "";
+	char ltr;
+	int num = 0;
+	int res = 0;
+	while(fn2[num] && !res) {
+		switch (fn2[num]) {
+			case ('*'):
+				snprintf(fn, sizeof(fn), "digits/star");
+				break;
+			case ('#'):
+				snprintf(fn, sizeof(fn), "digits/pound");
+				break;
+			case ('0'):
+			case ('1'):
+			case ('2'):
+			case ('3'):
+			case ('4'):
+			case ('5'):
+			case ('6'):
+			case ('7'):
+			case ('8'):
+				snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
+				break;
+			case ('@'):
+				strncpy(fn, "at", sizeof(fn));
+				break;
+			case (','):
+				strncpy(fn, "comma", sizeof(fn));
+				break;
+			case ('-'):
+				strncpy(fn, "dash", sizeof(fn));
+				break;
+			case ('.'):
+				strncpy(fn, "dot", sizeof(fn));
+				break;
+			case ('$'):
+				strncpy(fn, "dollar", sizeof(fn));
+				break;
+			case ('='):
+				strncpy(fn, "equals", sizeof(fn));
+				break;
+			case ('+'):
+				strncpy(fn, "plus", sizeof(fn));
+				break;
+			case ('/'):
+				strncpy(fn, "slash", sizeof(fn));
+				break;
+			case (' '):
+				strncpy(fn, "space", sizeof(fn));
+				break;
+			default:	/* '9' falls here... */
+				ltr = fn2[num];
+				if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';		/* file names are all lower-case */
+				snprintf(fn, sizeof(fn), "phonetic/%c", ltr);
+			}
+		/* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
 		res = ast_streamfile(chan, fn, lang);
 		if (!res) 
 			res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
@@ -74,14 +355,14 @@
 	/* XXX Should I be merged with say_digits_full XXX */
 	char fn2[256];
 	snprintf(fn2, sizeof(fn2), "%d", num);
-	return ast_say_digit_str(chan, fn2, ints, lang);
+	return ast_say_character_str(chan, fn2, ints, lang);
 }
 
 int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd)
 {
 	char fn2[256];
 	snprintf(fn2, sizeof(fn2), "%d", num);
-	return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
+	return ast_say_character_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
 }
 
 int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
Index: asterisk/apps/app_agi.c
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/app_agi.c,v
retrieving revision 1.31
diff -i -u -r1.31 app_agi.c
--- asterisk/apps/app_agi.c	12 Mar 2004 18:49:52 -0000	1.31
+++ asterisk/apps/app_agi.c	21 Mar 2004 04:40:44 -0000
@@ -384,11 +384,13 @@
 static int handle_saydigits(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 {
 	int res;
-	int num;
+/*	int num;
+*/
 	if (argc != 4)
 		return RESULT_SHOWUSAGE;
-	if (sscanf(argv[2], "%i", &num) != 1)
+/*	if (sscanf(argv[2], "%i", &num) != 1)
 		return RESULT_SHOWUSAGE;
+*/
 	res = ast_say_digit_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
 	if (res == 1) /* New command */
 		return RESULT_SUCCESS;
@@ -417,6 +419,26 @@
 		return RESULT_FAILURE;
 }
 
+static int handle_sayphonetic(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
+{
+	int res;
+/*	int num;
+*/
+	if (argc != 4)
+		return RESULT_SHOWUSAGE;
+/*	if (sscanf(argv[2], "%i", &num) != 1)
+		return RESULT_SHOWUSAGE;
+*/
+	res = ast_say_phonetic_str_full(chan, argv[2], argv[3], chan->language, agi->audio, agi->ctrl);
+	if (res == 1) /* New command */
+		return RESULT_SUCCESS;
+	fdprintf(agi->fd, "200 result=%d\n", res);
+	if (res >= 0)
+		return RESULT_SUCCESS;
+	else
+		return RESULT_FAILURE;
+}
+
 static int handle_getdata(struct ast_channel *chan, AGI *agi, int argc, char *argv[])
 {
 	int res;
@@ -1031,6 +1053,13 @@
 " completes without a digit being pressed, or the ASCII numerical value of the\n"
 " digit if one was pressed or -1 on error/hangup.\n";
 
+static char usage_sayphonetic[] =
+" Usage: SAY PHONETIC <string> <escape digits>\n"
+"        Say a given character string with phonetics, returning early if any of the given DTMF digits\n"
+" are received on the channel.  Returns 0 if playback completes without a digit\n"
+" being pressed, or the ASCII numerical value of the digit if one was pressed or\n"
+" -1 on error/hangup.\n";
+
 static char usage_getdata[] =
 " Usage: GET DATA <file to be streamed> [timeout] [max digits]\n"
 "	 Stream the given file, and recieve DTMF data. Returns the digits recieved\n"
@@ -1080,6 +1109,7 @@
 	{ { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
 	{ { "say", "digits", NULL }, handle_saydigits, "Says a given digit string", usage_saydigits },
 	{ { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
+        { { "say", "phonetic", NULL }, handle_sayphonetic, "Says a given character string with phonetics", usage_sayphonetic },
 	{ { "say", "time", NULL }, handle_saytime, "Says a given time", usage_saytime },
 	{ { "get", "data", NULL }, handle_getdata, "Gets data on a channel", usage_getdata },
 	{ { "set", "context", NULL }, handle_setcontext, "Sets channel context", usage_setcontext },
Index: asterisk/include/asterisk/say.h
===================================================================
RCS file: /usr/cvsroot/asterisk/include/asterisk/say.h,v
retrieving revision 1.7
diff -i -u -r1.7 say.h
--- asterisk/include/asterisk/say.h	13 Sep 2003 20:51:48 -0000	1.7
+++ asterisk/include/asterisk/say.h	21 Mar 2004 04:40:44 -0000
@@ -60,6 +60,10 @@
  */
 int ast_say_digit_str(struct ast_channel *chan, char *num, char *ints, char *lang);
 int ast_say_digit_str_full(struct ast_channel *chan, char *num, char *ints, char *lang, int audiofd, int ctrlfd);
+int ast_say_character_str(struct ast_channel *chan, char *num, char *ints, char *lang);
+int ast_say_character_str_full(struct ast_channel *chan, char *num, char *ints, char *lang, int audiofd, int ctrlfd);
+int ast_say_phonetic_str(struct ast_channel *chan, char *num, char *ints, char *lang);
+int ast_say_phonetic_str_full(struct ast_channel *chan, char *num, char *ints, char *lang, int audiofd, int ctrlfd);
 
 int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang);
 
