Commit 291d170b73 for asterisk.org

commit 291d170b73c1380a775883f26ffc39a4e7d81eee
Author: Sean Bright <sean@seanbright.com>
Date:   Wed Sep 23 19:30:11 2026 +0000

    say.c: Look for "and" in several locations, falling back to `vm-and`

    `vm-and` exists in all of the core sounds files that the project
    distributes, so while we will now try to find `digits/and` and `and`
    first, we always fallback to `vm-and`.

    Resolves: #622

diff --git a/main/say.c b/main/say.c
index 0aefd05f93..01f7feef7b 100644
--- a/main/say.c
+++ b/main/say.c
@@ -59,6 +59,7 @@
 #include "asterisk/cli.h" /* use ESS */

 /* Forward declaration */
+static const char *find_first_and(const char *lang);
 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);

 struct ast_str* ast_get_character_str(const char *str, const char *lang, enum ast_say_case_sensitivity sensitivity) {
@@ -414,7 +415,7 @@ static struct ast_str* ast_get_money_en_dollars_str(const char *str, const char

 		/* If dollars and cents, add "and" in the middle */
 		if (cents > 0) {
-			ast_str_append(&filenames, 0, "&%s", "and");
+			ast_str_append(&filenames, 0, "&%s", find_first_and(lang));
 		}
 	}

@@ -873,6 +874,17 @@ static int wait_file(struct ast_channel *chan, const char *ints, const char *fil
 	return res;
 }

+static const char *find_first_and(const char *language)
+{
+	if (ast_fileexists("digits/and", NULL, language)) {
+		return "digits/and";
+	} else if (ast_fileexists("and", NULL, language)) {
+		return "and";
+	} else {
+		return "vm-and";
+	}
+}
+
 /*! \brief  ast_say_number_full: call language-specific functions
      \note Called from AGI */
 static int say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
@@ -1113,7 +1125,7 @@ static int ast_say_number_full_da(struct ast_channel *chan, int num, const char
 			ast_copy_string(fn, "digits/hundred", sizeof(fn));
 			playh = 0;
 		} else if (playa) {
-			ast_copy_string(fn, "digits/and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			playa = 0;
 		} else if (num == 1 && cn == -1) {
 			ast_copy_string(fn, "digits/1N", sizeof(fn));
@@ -1493,7 +1505,7 @@ static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const ch
 			ast_copy_string(fn, "digits/hundred", sizeof(fn));
 			playh = 0;
 		} else if (playa) {
-			ast_copy_string(fn, "vm-and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			playa = 0;
 		} else if (num < 20) {
 			snprintf(fn, sizeof(fn), "digits/%d", num);
@@ -1655,7 +1667,7 @@ static int ast_say_number_full_es(struct ast_channel *chan, int num, const char
 				num = 0;
 			}
 		} else if (playa) {
-			ast_copy_string(fn, "digits/and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			playa = 0;
 		} else if (num == 1) {
 			if (mf < 0)
@@ -2109,7 +2121,7 @@ static int ast_say_number_full_is(struct ast_channel *chan, int num, const char
 				ast_copy_string(fn, "digits/hundred", sizeof(fn));
 			playh = 0;
 		} else if (playa) {
-			ast_copy_string(fn, "digits/and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			playa = 0;
 		} else if (num < 5 && cn == 2) {
 			snprintf(fn, sizeof(fn), "digits/%dkvk", num);
@@ -2476,7 +2488,7 @@ static int ast_say_number_full_no(struct ast_channel *chan, int num, const char
 			ast_copy_string(fn, "digits/hundred", sizeof(fn));
 			playh = 0;
 		} else if (playa) {
-			ast_copy_string(fn, "digits/and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			playa = 0;
 		} else if (num == 1 && cn == -1) {
 			ast_copy_string(fn, "digits/1N", sizeof(fn));
@@ -3826,7 +3838,7 @@ static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const
 				num = 0;
 			}
 		} else if (num < 100 && t) {
-			ast_copy_string(fn, "digits/and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			t = 0;
 		} else if (num < 20) {
 			snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
@@ -3989,7 +4001,7 @@ static int ast_say_enumeration_full_de(struct ast_channel *chan, int num, const
 				num = 0;
 			}
 		} else if (num < 100 && t) {
-			ast_copy_string(fn, "digits/and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			t = 0;
 		} else if (num < 20) {
 			snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
@@ -4240,7 +4252,7 @@ static int ast_say_enumeration_full_is(struct ast_channel *chan, int num, const
 				num = 0;
 			}
 		} else if (num < 100 && t) {
-			ast_copy_string(fn, "digits/and", sizeof(fn));
+			ast_copy_string(fn, find_first_and(language), sizeof(fn));
 			t = 0;
 		} else if (num < 20) {
 			snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
@@ -4254,7 +4266,7 @@ static int ast_say_enumeration_full_is(struct ast_channel *chan, int num, const
 				t++;
 			}
 			else if (t) {
-				snprintf(fn, sizeof(fn), "digits/and");
+				ast_copy_string(fn, find_first_and(language), sizeof(fn));
 				t = 0;
 			}
 			else {
@@ -5283,7 +5295,7 @@ int ast_say_date_with_format_da(struct ast_channel *chan, time_t t, const char *
 				break;
 			case 'S':
 				/* Seconds */
-				res = wait_file(chan, ints, "digits/and", lang);
+				res = wait_file(chan, ints, find_first_and(lang), lang);
 				if (!res) {
 					res = ast_say_number(chan, tm.tm_sec, ints, lang, "f");
 					if (!res) {
@@ -5492,7 +5504,7 @@ int ast_say_date_with_format_de(struct ast_channel *chan, time_t t, const char *
 				break;
 			case 'S':
 				/* Seconds */
-				res = wait_file(chan, ints, "digits/and", lang);
+				res = wait_file(chan, ints, find_first_and(lang), lang);
 				if (!res) {
 					res = ast_say_number(chan, tm.tm_sec, ints, lang, "f");
 					if (!res) {
@@ -5701,7 +5713,7 @@ int ast_say_date_with_format_is(struct ast_channel *chan, time_t t, const char *
 				break;
 			case 'S':
 				/* Seconds */
-				res = wait_file(chan, ints, "digits/and", lang);
+				res = wait_file(chan, ints, find_first_and(lang), lang);
 				if (!res) {
 					res = ast_say_number(chan, tm.tm_sec, ints, lang, "f");
 					/* Say minute/minutes depending on whether seconds end in 1 */
@@ -7063,7 +7075,7 @@ int ast_say_date_with_format_pl(struct ast_channel *chan, time_t thetime, const
 				break;
 			case 'S':
 				/* Seconds */
-				res = wait_file(chan, ints, "digits/and", lang);
+				res = wait_file(chan, ints, find_first_and(lang), lang);
 				if (!res) {
 					if (tm.tm_sec == 1) {
 						res = wait_file(chan, ints, "digits/1z", lang);