Index: pbx.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx.c,v retrieving revision 1.115 diff -u -r1.115 pbx.c --- pbx.c 26 Apr 2004 03:02:49 -0000 1.115 +++ pbx.c 28 Apr 2004 20:13:17 -0000 @@ -287,7 +287,7 @@ { "SayNumber", pbx_builtin_saynumber, "Say Number", -" SayNumber(digits): Says the passed number\n" }, +" SayNumber(digits[,gender]): Says the passed number\n" }, { "SayDigits", pbx_builtin_saydigits, "Say Digits", @@ -4568,9 +4568,29 @@ static int pbx_builtin_saynumber(struct ast_channel *chan, void *data) { int res = 0; - if (data && atoi((char *)data) ) - res = ast_say_number(chan, atoi((char *)data), "", chan->language); - return res; + char tmp[256]; + char *number = (char *) NULL; + char *options = (char *) NULL; + + + if (!data || !strlen((char *)data)) { + ast_log(LOG_WARNING, "SayNumber requires an argument (number)\n"); + return -1; + } + strncpy(tmp, (char *)data, sizeof(tmp)-1); + number=tmp; + strsep(&number, "|"); + options = strsep(&number, "|"); + if (options) { + if ( strcasecmp(options, "f") && strcasecmp(options,"m") && + strcasecmp(options, "c") && strcasecmp(options, "n") ) { + ast_log(LOG_WARNING, "SayNumber gender option is either 'f', 'm', 'c' or 'n'\n"); + return -1; + } + } + + + return res = ast_say_number(chan, atoi((char *) tmp), "", chan->language, options); } static int pbx_builtin_saydigits(struct ast_channel *chan, void *data) Index: say.c =================================================================== RCS file: /usr/cvsroot/asterisk/say.c,v retrieving revision 1.17 diff -u -r1.17 say.c --- say.c 28 Apr 2004 04:33:16 -0000 1.17 +++ say.c 28 Apr 2004 20:13:17 -0000 @@ -25,7 +25,10 @@ #include "asterisk.h" #include -#define DIGITS_DIR AST_SOUNDS "/digits/" +#define DIGITS_DIR "digits/" + +/* Forward declaration */ +static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang); int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang) { @@ -89,22 +92,95 @@ return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd); } +/* Forward declarations */ +/* Syntaxes supported, not really language codes. + en - English, Swedish, Norwegian + fr - French + da - Danish (maybe German - please check) + pt - Portuguese + es - Spanish + it - Italian + nl - Dutch + + For portuguese, we're using an option to saynumber() to indicate if the gender is male of female + This should also be implemented in _full version, really. + + OEJ 2004-04-25 +*/ + +static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); +static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); +static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); +static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); +static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd); +static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); +static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); +static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd); + +/*--- ast_say_number_full: call language-specific functions */ +/* Called from AGI */ int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) { + char *options=(char *) NULL; /* While waiting for a general hack for agi */ + + if (!strcasecmp(language, "no") || !strcasecmp(language,"se") || !strcasecmp(language,"en") ) { + return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "fr") ) { /* French syntax */ + return(ast_say_number_full_fr(chan, num, ints, language, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "de") ) { /* German syntax */ + return(ast_say_number_full_de(chan, num, ints, language, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "da") ) { /* Danish syntax */ + return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "it") ) { /* Italian syntax */ + return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "pt") ) { /* Portuguese syntax */ + return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "es") ) { /* Spanish syntax */ + return(ast_say_number_full_es(chan, num, ints, language, audiofd, ctrlfd)); + } else if (!strcasecmp(language, "nl") ) { /* Spanish syntax */ + return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd)); + } + + /* Default to english */ + return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd)); +} + +/*--- ast_say_number: call language-specific functions without file descriptors */ +int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language, char *options) +{ + if (!strcasecmp(language, "no") || !strcasecmp(language,"se") || !strcasecmp(language,"en") ) { + return(ast_say_number_full_en(chan, num, ints, language, -1, -1)); + } + /* French */ + if (!strcasecmp(language, "fr")) { /* French syntax */ + return(ast_say_number_full_fr(chan, num, ints, language, -1, -1)); + } else if (!strcasecmp(language, "da")) { /* Danish syntax */ + return(ast_say_number_full_da(chan, num, ints, language, options, -1, -1)); + } else if (!strcasecmp(language, "it")) { /* Italian syntax */ + return(ast_say_number_full_it(chan, num, ints, language, -1, -1)); + } else if (!strcasecmp(language, "pt")) { /* Portuguese syntax */ + return(ast_say_number_full_pt(chan, num, ints, language, options, -1, -1)); + } else if (!strcasecmp(language, "nl")) { /* Spanish syntax */ + return(ast_say_number_full_nl(chan, num, ints, language, -1, -1)); + } else if (!strcasecmp(language, "es")) { /* Spanish syntax */ + return(ast_say_number_full_es(chan, num, ints, language, -1, -1)); + } + + /* Default to english */ + return(ast_say_number_full_en(chan, num, ints, language, NULL, NULL)); +} + +/*--- ast_say_number_full_en: English syntax */ +/* This is the default syntax, if no other syntax defined in this file is used */ +static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) +{ int res = 0; int playh = 0; char fn[256] = ""; if (!num) return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); - if (0) { - /* XXX Only works for english XXX */ - } else { - /* Use english numbers if a given language is supported. */ - /* As a special case, Norwegian has the same numerical grammar - as English */ - if (strcasecmp(language, "no")) - language = "en"; - while(!res && (num || playh)) { + + while(!res && (num || playh)) { if (playh) { snprintf(fn, sizeof(fn), "digits/hundred"); playh = 0; @@ -123,14 +199,14 @@ num -= ((num / 100) * 100); } else { if (num < 1000000) { /* 1,000,000 */ - res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd); + res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd); if (res) return res; num = num % 1000; snprintf(fn, sizeof(fn), "digits/thousand"); } else { if (num < 1000000000) { /* 1,000,000,000 */ - res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd); + res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd); if (res) return res; num = num % 1000000; @@ -142,80 +218,723 @@ } } } - if (!res) { - res = ast_streamfile(chan, fn, language); - if (!res) - res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); - ast_stopstream(chan); - } + if (!res) { + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + + } - } } return res; } -int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language) + +/*--- ast_say_number_full_fr: French syntax */ +static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) { - /* XXX Should I be merged with ast_say_number_full XXX */ int res = 0; int playh = 0; + int playa = 0; /* For french */ char fn[256] = ""; if (!num) - return ast_say_digits(chan, 0,ints, language); - if (0) { - /* XXX Only works for english XXX */ - } else { - /* Use english numbers */ - language = "en"; - while(!res && (num || playh)) { - if (playh) { - snprintf(fn, sizeof(fn), "digits/hundred"); - playh = 0; - } else - if (num < 20) { - snprintf(fn, sizeof(fn), "digits/%d", num); + return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); + while(!res && (num || playh || playa)) { + if (playh) { + snprintf(fn, sizeof(fn), "digits/hundred"); + playh = 0; + } else + if (playa) { + snprintf(fn, sizeof(fn), "digits/et"); + playa = 0; + } else + if (num < 21) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num < 70) { + snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10); + if ((num % 10) == 1) playa++; + num = num % 10; + } else + if (num < 80) { + snprintf(fn, sizeof(fn), "digits/60"); + if ((num % 10) == 1) playa++; + num = num - 60; + } else + if (num < 100) { + snprintf(fn, sizeof(fn), "digits/80"); + num = num - 80; + } else + if (num < 200) { + snprintf(fn, sizeof(fn), "digits/hundred"); + num = num - 100; + } else + if (num < 1000) { + snprintf(fn, sizeof(fn), "digits/%d", (num/100)); + playh++; + num = num % 100; + } else + if (num < 2000) { + snprintf(fn, sizeof(fn), "digits/thousand"); + num = num - 1000; + } else + if (num < 1000000) { + res = ast_say_number_full_fr(chan, num / 1000, ints, language, audiofd, ctrlfd); + if (res) return res; + snprintf(fn, sizeof(fn), "digits/thousand"); + num = num % 1000; + } else + if (num < 1000000000) { + res = ast_say_number_full_fr(chan, num / 1000000, ints, language, audiofd, ctrlfd); + if (res) return res; + snprintf(fn, sizeof(fn), "digits/million"); + num = num % 1000000; + } else { + ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); + res = -1; + } + if (!res) { + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + + } + + + } + return res; +} + +/*--- ast_say_number_full_da: Danish syntax */ +/* New files: + In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and" + */ +static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) +{ + int res = 0; + int playh = 0; + int playa = 0; + int cn = 1; /* +1 = Commune; -1 = Neutrum */ + char fn[256] = ""; + if (!num) + return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); + + if (options && !strncasecmp(options, "n",1)) cn = -1; + + while(!res && (num || playh || playa )) { + /* The grammer for Danish numbers is the same as for English except + * for the following: + * - 1 exists in both commune ("en", file "1N") and neutrum ("et", file "1") + * - numbers 20 through 99 are said in reverse order, i.e. 21 is + * "one-and twenty" and 68 is "eight-and sixty". + * - "million" is different in singular and plural form + * - numbers > 1000 with zero as the third digit from last have an + * "and" before the last two digits, i.e. 2034 is "two thousand and + * four-and thirty" and 1000012 is "one million and twelve". + */ + if (playh) { + snprintf(fn, sizeof(fn), "digits/hundred"); + playh = 0; + } else + if (playa) { + snprintf(fn, sizeof(fn), "digits/and"); + playa = 0; + } else + if (num == 1 && cn == -1) { + snprintf(fn, sizeof(fn), "digits/1N"); num = 0; - } else - if (num < 100) { - snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); - num -= ((num / 10) * 10); - } else { - if (num < 1000){ - snprintf(fn, sizeof(fn), "digits/%d", (num/100)); - playh++; - num -= ((num / 100) * 100); - } else { - if (num < 1000000) { - res = ast_say_number(chan, num / 1000, ints, language); - if (res) - return res; - num = num % 1000; - snprintf(fn, sizeof(fn), "digits/thousand"); + } else + if (num < 20) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num < 100) { + int ones = num % 10; + if (ones) { + snprintf(fn, sizeof(fn), "digits/%d-and", ones); + num -= ones; + } else { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } + } else { + if (num < 1000) { + int hundreds = num / 100; + if (hundreds == 1) + snprintf(fn, sizeof(fn), "digits/1N"); + else + snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); + + playh++; + num -= 100 * hundreds; + if (num) + playa++; + + } else { + if (num < 1000000) { + res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd); + if (res) + return res; + num = num % 1000; + snprintf(fn, sizeof(fn), "digits/thousand"); + } else { + if (num < 1000000000) { + int millions = num / 1000000; + res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd); + if (res) + return res; + if (millions == 1) + snprintf(fn, sizeof(fn), "digits/million"); + else + snprintf(fn, sizeof(fn), "digits/millions"); + num = num % 1000000; } else { - if (num < 1000000000) { - res = ast_say_number(chan, num / 1000000, ints, language); - if (res) - return res; - num = num % 1000000; - snprintf(fn, sizeof(fn), "digits/million"); - } else { - ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); - res = -1; - } - } + ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); + res = -1; + } + } + if (num && num < 100) + playa++; + } + } + if (!res) { + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); } + ast_stopstream(chan); + } + + } + return res; +} + +/*--- ast_say_number_full_de: German syntax */ +/* New files: + In addition to English, the following sounds are required: "millions", "and" and "1-and" through "9-and" + */ +static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) +{ + int res = 0; + int playh = 0; + int playa = 0; + char fn[256] = ""; + if (!num) + return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); + + while(!res && (num || playh || playa )) { + /* The grammer for German numbers is the same as for English except + * for the following: + * - numbers 20 through 99 are said in reverse order, i.e. 21 is + * "one-and twenty" and 68 is "eight-and sixty". + * - "million" is different in singular and plural form + * - numbers > 1000 with zero as the third digit from last have an + * "and" before the last two digits, i.e. 2034 is "two thousand and + * four-and thirty" and 1000012 is "one million and twelve". + */ + if (playh) { + snprintf(fn, sizeof(fn), "digits/hundred"); + playh = 0; + } else + if (playa) { + snprintf(fn, sizeof(fn), "digits/and"); + playa = 0; + } else + if (num < 20) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num < 100) { + int ones = num % 10; + if (ones) { + snprintf(fn, sizeof(fn), "digits/%d-and", ones); + num -= ones; + } else { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } + } else { + if (num < 1000) { + int hundreds = num / 100; + if (hundreds == 1) + snprintf(fn, sizeof(fn), "digits/1N"); + else + snprintf(fn, sizeof(fn), "digits/%d", (num / 100)); + + playh++; + num -= 100 * hundreds; + if (num) + playa++; + + } else { + if (num < 1000000) { + res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd); + if (res) + return res; + num = num % 1000; + snprintf(fn, sizeof(fn), "digits/thousand"); + } else { + if (num < 1000000000) { + int millions = num / 1000000; + res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd); + if (res) + return res; + if (millions == 1) + snprintf(fn, sizeof(fn), "digits/million"); + else + snprintf(fn, sizeof(fn), "digits/millions"); + num = num % 1000000; + } else { + ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); + res = -1; + } + } + if (num && num < 100) + playa++; + } + } if (!res) { - res = ast_streamfile(chan, fn, language); - if (!res) - res = ast_waitstream(chan, ints); + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } ast_stopstream(chan); + } - } } return res; } + +/*------------ Portuguese ----------------------*/ +/* ast_say_number_full_pt: Portuguese syntax */ +/* For feminin all sound files end with F */ +/* 100E for 100+ something */ +/* What is "pt-e" */ +static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd) +{ + int res = 0; + int playh = 0; + int mf = 1; /* +1 = Masculin; -1 = Feminin */ + + char fn[256] = ""; + + if (!num) + return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); + + if (options && !strncasecmp(options, "f",1)) mf = -1; + + while(!res && num ) { + + if (num < 20) { + if ((num == 1 || num == 2) && (mf < 0)) + snprintf(fn, sizeof(fn), "digits/%dF", num); + else + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num < 100) { + snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10); + if (num % 10) + playh = 1; + num = num % 10; + } else + if (num < 1000) { + if (num == 100) + snprintf(fn, sizeof(fn), "digits/100"); + else if (num < 200) + snprintf(fn, sizeof(fn), "digits/100E"); + else { + if (mf < 0 && num > 199) + snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100); + else + snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100); + if (num % 100) + playh = 1; + } + num = num % 100; + } else + if (num < 1000000) { + if (num > 1999) { + res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd); + if (res) + return res; + } + snprintf(fn, sizeof(fn), "digits/1000"); + if ((num % 1000) && ((num % 1000) < 100 || !(num % 100))) + playh = 1; + num = num % 1000; + } else + if (num < 1000000000) { + res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd ); + if (res) + return res; + + if (num < 2000000) + snprintf(fn, sizeof(fn), "digits/1000000"); + else + snprintf(fn, sizeof(fn), "digits/1000000S"); + + if ((num % 1000000) && + // no thousands + ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) || + // no hundreds and below + (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) ) + playh = 1; + num = num % 1000000; + } + if (!res && playh) { + res = wait_file(chan, ints, "digits/pt-e", language); + ast_stopstream(chan); + playh = 0; + } + if (!res) { + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + + } + + } + return res; +} + + +/*--- ast_say_number_full_it: italian */ +static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) +{ + int res = 0; + int playh = 0; + int tempnum = 0; + char fn[256] = ""; + + if (!num) + return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); + + /* + Italian support + + Like english, numbers till 20 are a single 'word', and other + compound, but with exceptions. + For example 21 is not twenty-one, but is a single word in it. + Idem for 28 (ie when a the 2nd part of a compund number + starts with a wovel) + + There're exceptions also for hundred, thounsand and million. + In english 100 = one hundred, 200 is two hundred. + In italian 100 = cento , like to say hundred (without one), + 200 and more are like english. + + Same apply for thousand: + 1000 is one thousand in en, 2000 is two thousand. + In it we have 1000 = mille , 2000 = 2 mila + + For million(s) we use the plural, if more than one + Also, one million is abbreviated in it, like on-million, + or 'un milione', not 'uno milione'. + So the right file is provided. + */ + + while(!res && (num || playh)) { + if (playh) { + snprintf(fn, sizeof(fn), "digits/hundred"); + playh = 0; + } else + if (num < 20) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 21) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 28) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 31) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 38) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 41) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 48) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 51) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 58) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 61) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 68) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 71) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 78) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 81) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 88) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 91) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num == 98) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num < 100) { + snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10); + num -= ((num / 10) * 10); + } else { + if (num < 1000){ + if ((num / 100) > 1) { + snprintf(fn, sizeof(fn), "digits/%d", (num/100)); + playh++; + } + else { + snprintf(fn, sizeof(fn), "digits/hundred"); + } + num -= ((num / 100) * 100); + } else { + if (num < 1000000) { /* 1,000,000 */ + if ((num/1000) > 1) + res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd); + if (res) + return res; + tempnum = num; + num = num % 1000; + if ((tempnum / 1000) < 2) + snprintf(fn, sizeof(fn), "digits/thousand"); + else /* for 1000 it says mille, for >1000 (eg 2000) says mila */ + snprintf(fn, sizeof(fn), "digits/thousands"); + } else { + if (num < 1000000000) { /* 1,000,000,000 */ + if ((num / 1000000) > 1) + res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd); + if (res) + return res; + tempnum = num; + num = num % 1000000; + if ((tempnum / 1000000) < 2) + snprintf(fn, sizeof(fn), "digits/million"); + else + snprintf(fn, sizeof(fn), "digits/millions"); + } else { + ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); + res = -1; + } + } + } + } + if (!res) { + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + + } + } + return res; +} + + +/*--- ast_say_number_full_es: spanish syntax */ +/* New files: + Requires a few new audios: + 21.gsm thru 29.gsm, cien.gsm, mil.gsm, millon.gsm, millones.gsm, 100.gsm, 200.gsm, 300.gsm, 400.gsm, 500.gsm, 600.gsm, 700.gsm, 800.gsm, 900.gsm, y.gsm + */ +static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) +{ + int res = 0; + int playa = 0; + char fn[256] = ""; + if (!num) + return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); + while (!res && num) { + if (playa) { + snprintf(fn, sizeof(fn), "digits/y"); + playa = 0; + } else + if (num < 31) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num < 100) { + snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10); + num -= ((num/10)*10); + if (num) + playa++; + } else + if (num == 100) { + snprintf(fn, sizeof(fn), "digits/cien"); + num = 0; + } else { + if (num < 1000) { + snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100); + num -= ((num/100)*100); + } else { + if (num < 1000000) { + res = ast_say_number_full_es(chan, num / 1000, ints, language, audiofd, ctrlfd); + if (res) + return res; + num = num % 1000; + snprintf(fn, sizeof(fn), "digits/mil"); + } else { + if (num < 2147483640) { + res = ast_say_number_full_es(chan, num / 1000000, ints, language, audiofd, ctrlfd); + if (res) + return res; + if ((num/1000000) == 1) { + snprintf(fn, sizeof(fn), "digits/millon"); + } else { + snprintf(fn, sizeof(fn), "digits/millones"); + } + num = num % 1000000; + } else { + ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); + res = -1; + } + } + } + } + + if (!res) { + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + + } + + } + return res; +} + +/*--- ast_say_number_full_nl: dutch syntax */ +/* New files: ??? + */ +static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd) +{ + int res = 0; + int playh = 0; + int units = 0; + char fn[256] = ""; + if (!num) + return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd); + while (!res && (num || playh )) { + if (playh) { + snprintf(fn, sizeof(fn), "digits/hundred"); + playh = 0; + } else + if (num < 20) { + snprintf(fn, sizeof(fn), "digits/%d", num); + num = 0; + } else + if (num < 100) { + units = num % 10; + if (units > 0) { + res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd); + if (res) + return res; + num = num - units; + snprintf(fn, sizeof(fn), "digits/nl-en"); + } else { + snprintf(fn, sizeof(fn), "digits/%d", num - units); + num = 0; + } + } else { + if (num < 1000){ + snprintf(fn, sizeof(fn), "digits/%d", (num/100)); + playh++; + num -= ((num / 100) * 100); + } else { + if (num < 1000000) { /* 1,000,000 */ + res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd); + if (res) + return res; + num = num % 1000; + snprintf(fn, sizeof(fn), "digits/thousand"); + } else { + if (num < 1000000000) { /* 1,000,000,000 */ + res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd); + if (res) + return res; + num = num % 1000000; + snprintf(fn, sizeof(fn), "digits/million"); + } else { + ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num); + res = -1; + } + } + } + } + + if (!res) { + if(!ast_streamfile(chan, fn, language)) { + if (audiofd && ctrlfd) + res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); + else + res = ast_waitstream(chan, ints); + } + ast_stopstream(chan); + + } + + } + return res; +} + + int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang) { struct tm tm; @@ -235,12 +954,13 @@ res = ast_waitstream(chan, ints); } if (!res) - res = ast_say_number(chan, tm.tm_mday, ints, lang); + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL); + /* Should portuguese add a gender here? Defaults to masculin */ if (!res) res = ast_waitstream(chan, ints); if (!res) - res = ast_say_number(chan, tm.tm_year + 1900, ints, lang); + res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); return res; } @@ -550,21 +1270,21 @@ pm = 1; } if (!res) - res = ast_say_number(chan, hour, ints, lang); + res = ast_say_number(chan, hour, ints, lang, (char *) NULL); if (tm.tm_min > 9) { if (!res) - res = ast_say_number(chan, tm.tm_min, ints, lang); + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); } else if (tm.tm_min) { if (!res) - res = ast_streamfile(chan, "digits/oh", lang); + res = ast_streamfile(chan, "digits/oh", lang); /* This is very english ! */ if (!res) res = ast_waitstream(chan, ints); if (!res) - res = ast_say_number(chan, tm.tm_min, ints, lang); + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); } else { if (!res) - res = ast_streamfile(chan, "digits/oclock", lang); + res = ast_streamfile(chan, "digits/oclock", lang); /* This is very english ! */ if (!res) res = ast_waitstream(chan, ints); } @@ -600,7 +1320,7 @@ res = ast_waitstream(chan, ints); } if (!res) - res = ast_say_number(chan, tm.tm_mday, ints, lang); + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); hour = tm.tm_hour; if (!hour) @@ -612,18 +1332,18 @@ pm = 1; } if (!res) - res = ast_say_number(chan, hour, ints, lang); + res = ast_say_number(chan, hour, ints, lang, (char *) NULL); if (tm.tm_min > 9) { if (!res) - res = ast_say_number(chan, tm.tm_min, ints, lang); + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); } else if (tm.tm_min) { if (!res) res = ast_streamfile(chan, "digits/oh", lang); if (!res) res = ast_waitstream(chan, ints); if (!res) - res = ast_say_number(chan, tm.tm_min, ints, lang); + res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL); } else { if (!res) res = ast_streamfile(chan, "digits/oclock", lang); @@ -640,7 +1360,7 @@ if (!res) res = ast_waitstream(chan, ints); if (!res) - res = ast_say_number(chan, tm.tm_year + 1900, ints, lang); + res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL); return res; } @@ -667,7 +1387,7 @@ res = ast_waitstream(chan, ints); } if (!res) - res = ast_say_number(chan, tm.tm_mday, ints, lang); + res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL); } else if (daydiff) { /* Just what day of the week */ Index: channel.c =================================================================== RCS file: /usr/cvsroot/asterisk/channel.c,v retrieving revision 1.104 diff -u -r1.104 channel.c --- channel.c 27 Apr 2004 21:21:57 -0000 1.104 +++ channel.c 28 Apr 2004 20:13:18 -0000 @@ -2350,12 +2350,12 @@ res=ast_streamfile(chan,"vm-youhave",chan->language); res = ast_waitstream(chan, ""); if(min) { - res = ast_say_number(chan,min, AST_DIGIT_ANY, chan->language); + res = ast_say_number(chan,min, AST_DIGIT_ANY, chan->language, (char *) NULL); res=ast_streamfile(chan,"minutes",chan->language); res = ast_waitstream(chan, ""); } if(sec) { - res = ast_say_number(chan,sec, AST_DIGIT_ANY, chan->language); + res = ast_say_number(chan,sec, AST_DIGIT_ANY, chan->language, (char *) NULL); res=ast_streamfile(chan,"seconds",chan->language); res = ast_waitstream(chan, ""); } Index: include/asterisk/say.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/say.h,v retrieving revision 1.7 diff -u -r1.7 say.h --- include/asterisk/say.h 13 Sep 2003 20:51:48 -0000 1.7 +++ include/asterisk/say.h 28 Apr 2004 20:13:18 -0000 @@ -29,10 +29,11 @@ * \param num number to say on the channel * \param ints which dtmf to interrupt on * \param lang language to speak the number + * \param options set to 'f' for female, 'm' for masculine (used in portuguese) * Vocally says a number on a given channel * Returns 0 on success, DTMF digit on interrupt, -1 on failure */ -int ast_say_number(struct ast_channel *chan, int num, char *ints, char *lang); +int ast_say_number(struct ast_channel *chan, int num, char *ints, char *lang, char *options); /* Same as above with audiofd for received audio and returns 1 on ctrlfd being readable */ int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd); Index: apps/app_meetme.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_meetme.c,v retrieving revision 1.23 diff -u -r1.23 app_meetme.c --- apps/app_meetme.c 8 Apr 2004 19:38:26 -0000 1.23 +++ apps/app_meetme.c 28 Apr 2004 20:13:18 -0000 @@ -621,7 +621,7 @@ } else { if (chan->_state != AST_STATE_UP) ast_answer(chan); - res = ast_say_number(chan, count, "", chan->language); + res = ast_say_number(chan, count, "", chan->language, (char *) NULL); /* Needs gender */ } LOCAL_USER_REMOVE(u); return res; Index: apps/app_queue.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_queue.c,v retrieving revision 1.57 diff -u -r1.57 app_queue.c --- apps/app_queue.c 26 Apr 2004 23:22:33 -0000 1.57 +++ apps/app_queue.c 28 Apr 2004 20:13:19 -0000 @@ -370,7 +370,7 @@ goto posout; } else { res += play_file(qe->chan, qe->parent->sound_thereare); - res += ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language); + res += ast_say_number(qe->chan, qe->pos, AST_DIGIT_ANY, qe->chan->language, (char *) NULL); /* Needs gender */ res += play_file(qe->chan, qe->parent->sound_calls); } @@ -383,7 +383,7 @@ supposed to be only once and we have already said it, say it */ if (avgholdmins > 1 && (qe->parent->announceholdtime) && (!(qe->parent->announceholdtime==1 && qe->last_pos)) ) { res += play_file(qe->chan, qe->parent->sound_holdtime); - res += ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language); + res += ast_say_number(qe->chan, avgholdmins, AST_DIGIT_ANY, qe->chan->language, (char*) NULL); res += play_file(qe->chan, qe->parent->sound_minutes); } Index: apps/app_voicemail.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_voicemail.c,v retrieving revision 1.77 diff -u -r1.77 app_voicemail.c --- apps/app_voicemail.c 28 Apr 2004 04:33:16 -0000 1.77 +++ apps/app_voicemail.c 28 Apr 2004 20:13:20 -0000 @@ -1706,7 +1706,7 @@ static int say_and_wait(struct ast_channel *chan, int num) { int d; - d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language); + d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language, (char *) NULL); return d; } @@ -2270,7 +2270,7 @@ if (d) return d; for (x = start; x< 5; x++) { - if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language))) + if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL))) return d; d = play_and_wait(chan, "vm-for"); if (d) @@ -2634,7 +2634,7 @@ res = wait_file2(chan, vms, "vm-message"); if (msg && (msg != vms->lastmsg)) { if (!res) - res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language); + res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language, (char *) NULL); } } Index: apps/app_zapscan.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_zapscan.c,v retrieving revision 1.8 diff -u -r1.8 app_zapscan.c --- apps/app_zapscan.c 10 Apr 2004 02:49:06 -0000 1.8 +++ apps/app_zapscan.c 28 Apr 2004 20:13:20 -0000 @@ -322,7 +322,7 @@ } confno = atoi(strchr(confstr,'/') + 1); ast_stopstream(chan); - ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language); + ast_say_number(chan, confno, AST_DIGIT_ANY, chan->language, (char *) NULL); res = conf_run(chan, confno, confflags); if (res<0) break; input = res;