2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
7 * George Konstantoulakis <gkon@inaccessnetworks.com>
9 * See http://www.asterisk.org for more information about
10 * the Asterisk project. Please do not directly contact
11 * any of the maintainers of this project for assistance;
12 * the project provides a web site, mailing lists and IRC
13 * channels for your use.
15 * This program is free software, distributed under the terms of
16 * the GNU General Public License Version 2. See the LICENSE file
17 * at the top of the source tree.
22 * \brief Say numbers and dates (maybe words one day too)
24 * \author Mark Spencer <markster@digium.com>
26 * \note 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr) George Konstantoulakis <gkon@inaccessnetworks.com>
28 * \note 2007-02-08 : Support for Georgian added by Alexander Shaduri <ashaduri@gmail.com>,
29 * Next Generation Networks (NGN).
34 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
36 #include <sys/types.h>
39 #include <netinet/in.h>
46 #include <iso/limits_iso.h>
49 #include "asterisk/file.h"
50 #include "asterisk/channel.h"
51 #include "asterisk/logger.h"
52 #include "asterisk/options.h"
53 #include "asterisk/say.h"
54 #include "asterisk/lock.h"
55 #include "asterisk/localtime.h"
56 #include "asterisk/utils.h"
58 /* Forward declaration */
59 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
62 static int say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
80 fn = "letters/exclaimation-point";
86 fn = "letters/dollar";
95 fn = "letters/equals";
101 fn = "letters/slash";
104 fn = "letters/space";
116 strcpy(fnbuf, "digits/X");
122 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
123 strcpy(fnbuf, "letters/X");
127 res = ast_streamfile(chan, fn, lang);
129 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
130 ast_stopstream(chan);
137 static int say_phonetic_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
155 fn = "letters/exclaimation-point";
161 fn = "letters/dollar";
170 fn = "letters/equals";
176 fn = "letters/slash";
179 fn = "letters/space";
190 strcpy(fnbuf, "digits/X");
194 default: /* '9' falls here... */
196 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
197 strcpy(fnbuf, "phonetic/X_p");
201 res = ast_streamfile(chan, fn, lang);
203 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
204 ast_stopstream(chan);
211 static int say_digit_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
218 while (str[num] && !res) {
240 strcpy(fnbuf, "digits/X");
246 res = ast_streamfile(chan, fn, lang);
248 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
249 ast_stopstream(chan);
257 /* Forward declarations */
258 /*! \page Def_syntaxlang Asterisk Language Syntaxes supported
259 \note Not really language codes.
260 For these language codes, Asterisk will change the syntax when
261 saying numbers (and in some cases dates and voicemail messages
265 \arg \b en - English (US)
266 \arg \b en_GB - English (British)
267 \arg \b es - Spanish, Mexican
272 \arg \b no - Norwegian
274 \arg \b pt - Portuguese
275 \arg \b pt_BR - Portuguese (Brazil)
277 \arg \b tw - Taiwanese / Chinese
279 \arg \b ge - Georgian
280 \arg \b hu - Hungarian
283 For Some languages the numbers differ for gender and plural.
284 \arg Use the option argument 'f' for female, 'm' for male and 'n' for neuter in languages like Portuguese, French, Spanish and German.
285 \arg use the option argument 'c' is for commune and 'n' for neuter gender in nordic languages like Danish, Swedish and Norwegian.
286 use the option argument 'p' for plural enumerations like in German
288 Date/Time functions currently have less languages supported than saynumber().
290 \todo Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
292 See contrib/i18n.testsuite.conf for some examples of the different syntaxes
295 Portuguese sound files needed for Time/Date functions:
306 Spanish sound files needed for Time/Date functions:
311 Italian sound files needed for Time/Date functions:
317 /* Forward declarations of language specific variants of ast_say_number_full */
318 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
319 static int ast_say_number_full_cz(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
320 static int ast_say_number_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
321 static int ast_say_number_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
322 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
323 static int ast_say_number_full_es(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
324 static int ast_say_number_full_fr(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
325 static int ast_say_number_full_he(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
326 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
327 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
328 static int ast_say_number_full_no(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
329 static int ast_say_number_full_pl(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
330 static int ast_say_number_full_pt(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
331 static int ast_say_number_full_se(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
332 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
333 static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
334 static int ast_say_number_full_ru(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
335 static int ast_say_number_full_ge(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
336 static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
338 /* Forward declarations of language specific variants of ast_say_enumeration_full */
339 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
340 static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
341 static int ast_say_enumeration_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
343 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
344 static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
345 static int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
346 static int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
347 static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
348 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
349 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
350 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
351 static int ast_say_date_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
352 static int ast_say_date_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
354 static int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
355 static int ast_say_date_with_format_da(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
356 static int ast_say_date_with_format_de(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
357 static int ast_say_date_with_format_es(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
358 static int ast_say_date_with_format_he(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
359 static int ast_say_date_with_format_fr(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
360 static int ast_say_date_with_format_it(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
361 static int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
362 static int ast_say_date_with_format_pl(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
363 static int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
364 static int ast_say_date_with_format_tw(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
365 static int ast_say_date_with_format_gr(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone);
367 static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
368 static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
369 static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
370 static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
371 static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
372 static int ast_say_time_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
373 static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
374 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
375 static int ast_say_time_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
376 static int ast_say_time_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
378 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
379 static int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
380 static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
381 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
382 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
383 static int ast_say_datetime_pt_BR(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
384 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
385 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
386 static int ast_say_datetime_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
387 static int ast_say_datetime_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
389 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
390 static int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
391 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
392 static int ast_say_datetime_from_now_ge(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
394 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang)
397 if ((res = ast_streamfile(chan, file, lang)))
398 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
400 res = ast_waitstream(chan, ints);
404 /*! \brief ast_say_number_full: call language-specific functions */
405 /* Called from AGI */
406 static int say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
408 if (!strcasecmp(language,"en") ) { /* English syntax */
409 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
410 } else if (!strcasecmp(language, "cz") ) { /* Czech syntax */
411 return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd));
412 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
413 return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
414 } else if (!strcasecmp(language, "de") ) { /* German syntax */
415 return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
416 } else if (!strcasecmp(language, "en_GB") ) { /* British syntax */
417 return(ast_say_number_full_en_GB(chan, num, ints, language, audiofd, ctrlfd));
418 } else if (!strcasecmp(language, "no") ) { /* Norwegian syntax */
419 return(ast_say_number_full_no(chan, num, ints, language, options, audiofd, ctrlfd));
420 } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) { /* Spanish syntax */
421 return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd));
422 } else if (!strcasecmp(language, "fr") ) { /* French syntax */
423 return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd));
424 } else if (!strcasecmp(language, "he") ) { /* Hebrew syntax */
425 return(ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd));
426 } else if (!strcasecmp(language, "hu") ) { /* Hungarian syntax */
427 return(ast_say_number_full_hu(chan, num, ints, language, audiofd, ctrlfd));
428 } else if (!strcasecmp(language, "it") ) { /* Italian syntax */
429 return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd));
430 } else if (!strcasecmp(language, "nl") ) { /* Dutch syntax */
431 return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd));
432 } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */
433 return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd));
434 } else if (!strcasecmp(language, "pt") || !strcasecmp(language, "pt_BR")) { /* Portuguese syntax */
435 return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd));
436 } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */
437 return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd));
438 } else if (!strcasecmp(language, "tw") || !strcasecmp(language, "zh") ) { /* Taiwanese / Chinese syntax */
439 return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd));
440 } else if (!strcasecmp(language, "gr") ) { /* Greek syntax */
441 return(ast_say_number_full_gr(chan, num, ints, language, audiofd, ctrlfd));
442 } else if (!strcasecmp(language, "ru") ) { /* Russian syntax */
443 return(ast_say_number_full_ru(chan, num, ints, language, options, audiofd, ctrlfd));
444 } else if (!strcasecmp(language, "ge") ) { /* Georgian syntax */
445 return(ast_say_number_full_ge(chan, num, ints, language, options, audiofd, ctrlfd));
448 /* Default to english */
449 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
452 /*! \brief ast_say_number_full_en: English syntax */
453 /* This is the default syntax, if no other syntax defined in this file is used */
454 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
460 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
462 while (!res && (num || playh)) {
464 snprintf(fn, sizeof(fn), "digits/minus");
465 if ( num > INT_MIN ) {
471 snprintf(fn, sizeof(fn), "digits/hundred");
473 } else if (num < 20) {
474 snprintf(fn, sizeof(fn), "digits/%d", num);
476 } else if (num < 100) {
477 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
478 num -= ((num / 10) * 10);
481 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
483 num -= ((num / 100) * 100);
485 if (num < 1000000) { /* 1,000,000 */
486 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
490 snprintf(fn, sizeof(fn), "digits/thousand");
492 if (num < 1000000000) { /* 1,000,000,000 */
493 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
497 snprintf(fn, sizeof(fn), "digits/million");
500 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
507 if (!ast_streamfile(chan, fn, language)) {
508 if ((audiofd > -1) && (ctrlfd > -1))
509 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
511 res = ast_waitstream(chan, ints);
513 ast_stopstream(chan);
519 static int exp10_int(int power)
522 for (x=0;x<power;x++)
527 /*! \brief ast_say_number_full_cz: Czech syntax */
529 * 1m,2m - gender male
530 * 1w,2w - gender female
534 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set
536 * for each number 10^(3n + 3) exist 3 files represented as:
537 * 1 tousand = jeden tisic = 1_E3
538 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
539 * 5,6,... tousands = pet,sest,... tisic = 5_E3
545 * tousand, milion are gender male, so 1 and 2 is 1m 2m
546 * miliard is gender female, so 1 and 2 is 1w 2w
548 static int ast_say_number_full_cz(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
558 /* options - w = woman, m = man, n = neutral. Defaultl is woman */
563 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
565 while (!res && (num || playh)) {
567 snprintf(fn, sizeof(fn), "digits/minus");
568 if ( num > INT_MIN ) {
573 } else if (num < 3 ) {
574 snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]);
577 } else if (num < 20) {
578 snprintf(fn, sizeof(fn), "digits/%d",num);
581 } else if (num < 100) {
582 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
583 num -= ((num / 10) * 10);
584 } else if (num < 1000) {
585 hundered = num / 100;
586 if ( hundered == 1 ) {
587 snprintf(fn, sizeof(fn), "digits/1sto");
588 } else if ( hundered == 2 ) {
589 snprintf(fn, sizeof(fn), "digits/2ste");
591 res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd);
594 if (hundered == 3 || hundered == 4) {
595 snprintf(fn, sizeof(fn), "digits/sta");
596 } else if ( hundered > 4 ) {
597 snprintf(fn, sizeof(fn), "digits/set");
600 num -= (hundered * 100);
601 } else { /* num > 1000 */
602 length = (int)log10(num)+1;
603 while ( (length % 3 ) != 1 ) {
606 left = num / (exp10_int(length-1));
609 case 9: options = "w"; /* 1,000,000,000 gender female */
611 default : options = "m"; /* others are male */
614 if ( left > 1 ) { /* we dont say "one thousand" but only thousand */
615 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd);
619 if ( left >= 5 ) { /* >= 5 have the same declesion */
620 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1);
621 } else if ( left >= 2 && left <= 4 ) {
622 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1);
623 } else { /* left == 1 */
624 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1);
626 num -= left * (exp10_int(length-1));
629 if (!ast_streamfile(chan, fn, language)) {
630 if ((audiofd > -1) && (ctrlfd > -1)) {
631 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
633 res = ast_waitstream(chan, ints);
636 ast_stopstream(chan);
642 /*! \brief ast_say_number_full_da: Danish syntax */
644 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and"
646 static int ast_say_number_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
651 int cn = 1; /* +1 = commune; -1 = neuter */
654 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
656 if (options && !strncasecmp(options, "n",1)) cn = -1;
658 while (!res && (num || playh || playa )) {
659 /* The grammar for Danish numbers is the same as for English except
661 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1")
662 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
663 * "one-and twenty" and 68 is "eight-and sixty".
664 * - "million" is different in singular and plural form
665 * - numbers > 1000 with zero as the third digit from last have an
666 * "and" before the last two digits, i.e. 2034 is "two thousand and
667 * four-and thirty" and 1000012 is "one million and twelve".
670 snprintf(fn, sizeof(fn), "digits/minus");
671 if ( num > INT_MIN ) {
677 snprintf(fn, sizeof(fn), "digits/hundred");
680 snprintf(fn, sizeof(fn), "digits/and");
682 } else if (num == 1 && cn == -1) {
683 snprintf(fn, sizeof(fn), "digits/1N");
685 } else if (num < 20) {
686 snprintf(fn, sizeof(fn), "digits/%d", num);
688 } else if (num < 100) {
691 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
694 snprintf(fn, sizeof(fn), "digits/%d", num);
699 int hundreds = num / 100;
701 snprintf(fn, sizeof(fn), "digits/1N");
703 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
706 num -= 100 * hundreds;
712 res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
716 snprintf(fn, sizeof(fn), "digits/thousand");
718 if (num < 1000000000) {
719 int millions = num / 1000000;
720 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
724 snprintf(fn, sizeof(fn), "digits/million");
726 snprintf(fn, sizeof(fn), "digits/millions");
730 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
734 if (num && num < 100)
739 if (!ast_streamfile(chan, fn, language)) {
740 if ((audiofd > -1) && (ctrlfd > -1))
741 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
743 res = ast_waitstream(chan, ints);
745 ast_stopstream(chan);
751 /*! \brief ast_say_number_full_de: German syntax */
753 In addition to English, the following sounds are required:
755 "1-and" through "9-and"
758 NB "1" is recorded as 'eins'
760 static int ast_say_number_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
763 int mf = 1; /* +1 = male and neuter; -1 = female */
767 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
769 if (options && (!strncasecmp(options, "f",1)))
772 while (!res && num) {
773 /* The grammar for German numbers is the same as for English except
775 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
776 * "one-and twenty" and 68 is "eight-and sixty".
777 * - "one" varies according to gender
778 * - 100 is 'hundert', however all other instances are 'ein hundert'
779 * - 1000 is 'tausend', however all other instances are 'ein tausend'
780 * - 1000000 is always 'eine million'
781 * - "million" is different in singular and plural form
784 snprintf(fn, sizeof(fn), "digits/minus");
785 if ( num > INT_MIN ) {
790 } else if (num < 100 && t) {
791 snprintf(fn, sizeof(fn), "digits/and");
793 } else if (num == 1 && mf == -1) {
794 snprintf(fn, sizeof(fn), "digits/%dF", num);
796 } else if (num < 20) {
797 snprintf(fn, sizeof(fn), "digits/%d", num);
799 } else if (num < 100) {
802 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
805 snprintf(fn, sizeof(fn), "digits/%d", num);
808 } else if (num == 100 && t == 0) {
809 snprintf(fn, sizeof(fn), "digits/hundred");
811 } else if (num < 1000) {
812 int hundreds = num / 100;
815 snprintf(fn, sizeof(fn), "digits/1N");
817 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
819 snprintf(fna, sizeof(fna), "digits/hundred");
821 } else if (num == 1000 && t == 0) {
822 snprintf(fn, sizeof(fn), "digits/thousand");
824 } else if (num < 1000000) {
825 int thousands = num / 1000;
828 if (thousands == 1) {
829 snprintf(fn, sizeof(fn), "digits/1N");
830 snprintf(fna, sizeof(fna), "digits/thousand");
832 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
835 snprintf(fn, sizeof(fn), "digits/thousand");
837 } else if (num < 1000000000) {
838 int millions = num / 1000000;
842 snprintf(fn, sizeof(fn), "digits/1F");
843 snprintf(fna, sizeof(fna), "digits/million");
845 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
848 snprintf(fn, sizeof(fn), "digits/millions");
850 } else if (num <= INT_MAX) {
851 int billions = num / 1000000000;
852 num = num % 1000000000;
855 snprintf(fn, sizeof(fn), "digits/1F");
856 snprintf(fna, sizeof(fna), "digits/milliard");
858 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
862 snprintf(fn, sizeof(fn), "digits/milliards");
866 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
870 if (!ast_streamfile(chan, fn, language)) {
871 if ((audiofd > -1) && (ctrlfd > -1))
872 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
874 res = ast_waitstream(chan, ints);
876 ast_stopstream(chan);
878 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
879 if ((audiofd > -1) && (ctrlfd > -1))
880 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
882 res = ast_waitstream(chan, ints);
884 ast_stopstream(chan);
892 /*! \brief ast_say_number_full_en_GB: British and Norwegian syntax */
894 In addition to American English, the following sounds are required: "and"
896 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
903 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
905 while (!res && (num || playh || playa )) {
907 snprintf(fn, sizeof(fn), "digits/minus");
908 if ( num > INT_MIN ) {
914 snprintf(fn, sizeof(fn), "digits/hundred");
917 snprintf(fn, sizeof(fn), "digits/and");
919 } else if (num < 20) {
920 snprintf(fn, sizeof(fn), "digits/%d", num);
922 } else if (num < 100) {
923 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
924 num -= ((num / 10) * 10);
925 } else if (num < 1000) {
926 int hundreds = num / 100;
927 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
930 num -= 100 * hundreds;
933 } else if (num < 1000000) {
934 res = ast_say_number_full_en_GB(chan, num / 1000, ints, language, audiofd, ctrlfd);
937 snprintf(fn, sizeof(fn), "digits/thousand");
939 if (num && num < 100)
941 } else if (num < 1000000000) {
942 int millions = num / 1000000;
943 res = ast_say_number_full_en_GB(chan, millions, ints, language, audiofd, ctrlfd);
946 snprintf(fn, sizeof(fn), "digits/million");
948 if (num && num < 100)
952 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
957 if (!ast_streamfile(chan, fn, language)) {
958 if ((audiofd > -1) && (ctrlfd > -1))
959 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
961 res = ast_waitstream(chan, ints);
963 ast_stopstream(chan);
969 /*! \brief ast_say_number_full_es: Spanish syntax */
971 Requires a few new audios:
972 1F.gsm: feminine 'una'
973 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
975 static int ast_say_number_full_es(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
979 int mf = 0; /* +1 = male; -1 = female */
982 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
985 if (!strncasecmp(options, "f",1))
987 else if (!strncasecmp(options, "m", 1))
991 while (!res && num) {
993 snprintf(fn, sizeof(fn), "digits/minus");
994 if ( num > INT_MIN ) {
1000 snprintf(fn, sizeof(fn), "digits/and");
1002 } else if (num == 1) {
1004 snprintf(fn, sizeof(fn), "digits/%dF", num);
1006 snprintf(fn, sizeof(fn), "digits/%dM", num);
1008 snprintf(fn, sizeof(fn), "digits/%d", num);
1010 } else if (num < 31) {
1011 snprintf(fn, sizeof(fn), "digits/%d", num);
1013 } else if (num < 100) {
1014 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1015 num -= ((num/10)*10);
1018 } else if (num == 100) {
1019 snprintf(fn, sizeof(fn), "digits/100");
1021 } else if (num < 200) {
1022 snprintf(fn, sizeof(fn), "digits/100-and");
1026 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
1027 num -= ((num/100)*100);
1028 } else if (num < 2000) {
1030 snprintf(fn, sizeof(fn), "digits/thousand");
1032 if (num < 1000000) {
1033 res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1037 snprintf(fn, sizeof(fn), "digits/thousand");
1039 if (num < 2147483640) {
1040 if ((num/1000000) == 1) {
1041 res = ast_say_number_full_es(chan, num / 1000000, ints, language, "M", audiofd, ctrlfd);
1044 snprintf(fn, sizeof(fn), "digits/million");
1046 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1049 snprintf(fn, sizeof(fn), "digits/millions");
1051 num = num % 1000000;
1054 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1062 if (!ast_streamfile(chan, fn, language)) {
1063 if ((audiofd > -1) && (ctrlfd > -1))
1064 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1066 res = ast_waitstream(chan, ints);
1068 ast_stopstream(chan);
1076 /*! \brief ast_say_number_full_fr: French syntax */
1077 /* Extra sounds needed:
1080 static int ast_say_number_full_fr(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1085 int mf = 1; /* +1 = male; -1 = female */
1088 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1090 if (options && !strncasecmp(options, "f",1))
1093 while (!res && (num || playh || playa)) {
1095 snprintf(fn, sizeof(fn), "digits/minus");
1096 if ( num > INT_MIN ) {
1102 snprintf(fn, sizeof(fn), "digits/hundred");
1105 snprintf(fn, sizeof(fn), "digits/et");
1107 } else if (num == 1) {
1109 snprintf(fn, sizeof(fn), "digits/%dF", num);
1111 snprintf(fn, sizeof(fn), "digits/%d", num);
1113 } else if (num < 21) {
1114 snprintf(fn, sizeof(fn), "digits/%d", num);
1116 } else if (num < 70) {
1117 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1118 if ((num % 10) == 1) playa++;
1120 } else if (num < 80) {
1121 snprintf(fn, sizeof(fn), "digits/60");
1122 if ((num % 10) == 1) playa++;
1124 } else if (num < 100) {
1125 snprintf(fn, sizeof(fn), "digits/80");
1127 } else if (num < 200) {
1128 snprintf(fn, sizeof(fn), "digits/hundred");
1130 } else if (num < 1000) {
1131 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1134 } else if (num < 2000) {
1135 snprintf(fn, sizeof(fn), "digits/thousand");
1137 } else if (num < 1000000) {
1138 res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1141 snprintf(fn, sizeof(fn), "digits/thousand");
1143 } else if (num < 1000000000) {
1144 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1147 snprintf(fn, sizeof(fn), "digits/million");
1148 num = num % 1000000;
1151 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1155 if (!ast_streamfile(chan, fn, language)) {
1156 if ((audiofd > -1) && (ctrlfd > -1))
1157 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1159 res = ast_waitstream(chan, ints);
1161 ast_stopstream(chan);
1169 /*! \brief ast_say_number_full_he: Hebrew syntax */
1170 /* Extra sounds needed:
1174 2hundred: 2 hundreds
1175 2thousands: 2 thousand
1176 thousands: plural of 'thousand'
1177 3sF 'Smichut forms (female)
1184 3s 'Smichut' forms (male)
1201 TODO: 've' should sometimed be 'hu':
1202 * before 'shtaym' (2, F)
1203 * before 'shnaym' (2, M)
1204 * before 'shlosha' (3, M)
1205 * before 'shmone' (8, M)
1206 * before 'shlosim' (30)
1207 * before 'shmonim' (80)
1213 #define SAY_NUM_BUF_SIZE 256
1214 static int ast_say_number_full_he(struct ast_channel *chan, int num,
1215 const char *ints, const char *language, const char *options,
1216 int audiofd, int ctrlfd)
1219 int state = 0; /* no need to save anything */
1220 int mf = 1; /* +1 = Masculin; -1 = Feminin */
1221 char fn[SAY_NUM_BUF_SIZE] = "";
1222 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: started. "
1223 "num: %d, options=\"%s\"\n",
1227 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1229 if (options && !strncasecmp(options, "f",1))
1232 /* Do we have work to do? */
1233 while (!res && (num || (state>0) )) {
1234 /* first type of work: play a second sound. In this loop
1235 * we can only play one sound file at a time. Thus playing
1236 * a second one requires repeating the loop just for the
1237 * second file. The variable 'state' remembers where we were.
1238 * state==0 is the normal mode and it means that we continue
1239 * to check if the number num has yet anything left.
1241 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: num: %d, "
1242 "state=%d, options=\"%s\", mf=%d\n",
1243 num, state, options, mf
1246 snprintf(fn, sizeof(fn), "digits/hundred");
1248 } else if (state==2) {
1249 snprintf(fn, sizeof(fn), "digits/ve");
1251 } else if (state==3) {
1252 snprintf(fn, sizeof(fn), "digits/thousands");
1254 } else if (num <21) {
1256 snprintf(fn, sizeof(fn), "digits/%dF", num);
1258 snprintf(fn, sizeof(fn), "digits/%d", num);
1260 } else if (num < 100) {
1261 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1264 } else if (num < 200) {
1265 snprintf(fn, sizeof(fn), "digits/1hundred");
1268 } else if (num < 300) {
1269 snprintf(fn, sizeof(fn), "digits/2hundred");
1272 } else if (num < 1000) {
1273 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1276 } else if (num < 2000) {
1277 snprintf(fn, sizeof(fn), "digits/thousand");
1279 } else if (num < 3000) {
1280 snprintf(fn, sizeof(fn), "digits/2thousand");
1283 } else if (num < 20000) {
1284 snprintf(fn, sizeof(fn), "digits/%ds",(num/1000));
1287 } else if (num < 1000000) {
1288 res = ast_say_number_full_he(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1291 snprintf(fn, sizeof(fn), "digits/thousand");
1293 } else if (num < 1000000000) {
1294 res = ast_say_number_full_he(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1297 snprintf(fn, sizeof(fn), "digits/million");
1298 num = num % 1000000;
1301 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1305 if (!ast_streamfile(chan, fn, language)) {
1306 if ((audiofd > -1) && (ctrlfd > -1))
1307 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1309 res = ast_waitstream(chan, ints);
1311 ast_stopstream(chan);
1317 /*! \brief ast_say_number_full_hu: Hungarian syntax */
1318 /* Extra sounds need:
1322 static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1328 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1332 like english, except numbers up to 29 are from 2 words.
1333 10 and first word of 1[1-9] and 20 and first word of 2[1-9] are different.
1336 while(!res && (num || playh)) {
1338 snprintf(fn, sizeof(fn), "digits/minus");
1339 if ( num > INT_MIN ) {
1345 snprintf(fn, sizeof(fn), "digits/hundred");
1347 } else if (num < 11 || num == 20) {
1348 snprintf(fn, sizeof(fn), "digits/%d", num);
1350 } else if (num < 20) {
1351 snprintf(fn, sizeof(fn), "digits/10en");
1353 } else if (num < 30) {
1354 snprintf(fn, sizeof(fn), "digits/20on");
1356 } else if (num < 100) {
1357 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1358 num -= ((num / 10) * 10);
1361 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1363 num -= ((num / 100) * 100);
1365 if (num < 1000000) { /* 1,000,000 */
1366 res = ast_say_number_full_hu(chan, num / 1000, ints, language, audiofd, ctrlfd);
1370 snprintf(fn, sizeof(fn), "digits/thousand");
1372 if (num < 1000000000) { /* 1,000,000,000 */
1373 res = ast_say_number_full_hu(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1376 num = num % 1000000;
1377 snprintf(fn, sizeof(fn), "digits/million");
1379 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1386 if(!ast_streamfile(chan, fn, language)) {
1387 if ((audiofd > -1) && (ctrlfd > -1))
1388 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1390 res = ast_waitstream(chan, ints);
1392 ast_stopstream(chan);
1398 /*! \brief ast_say_number_full_it: Italian */
1399 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1407 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1412 Like english, numbers up to 20 are a single 'word', and others
1413 compound, but with exceptions.
1414 For example 21 is not twenty-one, but there is a single word in 'it'.
1415 Idem for 28 (ie when a the 2nd part of a compund number
1416 starts with a vowel)
1418 There are exceptions also for hundred, thousand and million.
1419 In english 100 = one hundred, 200 is two hundred.
1420 In italian 100 = cento , like to say hundred (without one),
1421 200 and more are like english.
1423 Same applies for thousand:
1424 1000 is one thousand in en, 2000 is two thousand.
1425 In it we have 1000 = mille , 2000 = 2 mila
1427 For million(s) we use the plural, if more than one
1428 Also, one million is abbreviated in it, like on-million,
1429 or 'un milione', not 'uno milione'.
1430 So the right file is provided.
1433 while (!res && (num || playh)) {
1435 snprintf(fn, sizeof(fn), "digits/minus");
1436 if ( num > INT_MIN ) {
1442 snprintf(fn, sizeof(fn), "digits/hundred");
1444 } else if (num < 20) {
1445 snprintf(fn, sizeof(fn), "digits/%d", num);
1447 } else if (num == 21) {
1448 snprintf(fn, sizeof(fn), "digits/%d", num);
1450 } else if (num == 28) {
1451 snprintf(fn, sizeof(fn), "digits/%d", num);
1453 } else if (num == 31) {
1454 snprintf(fn, sizeof(fn), "digits/%d", num);
1456 } else if (num == 38) {
1457 snprintf(fn, sizeof(fn), "digits/%d", num);
1459 } else if (num == 41) {
1460 snprintf(fn, sizeof(fn), "digits/%d", num);
1462 } else if (num == 48) {
1463 snprintf(fn, sizeof(fn), "digits/%d", num);
1465 } else if (num == 51) {
1466 snprintf(fn, sizeof(fn), "digits/%d", num);
1468 } else if (num == 58) {
1469 snprintf(fn, sizeof(fn), "digits/%d", num);
1471 } else if (num == 61) {
1472 snprintf(fn, sizeof(fn), "digits/%d", num);
1474 } else if (num == 68) {
1475 snprintf(fn, sizeof(fn), "digits/%d", num);
1477 } else if (num == 71) {
1478 snprintf(fn, sizeof(fn), "digits/%d", num);
1480 } else if (num == 78) {
1481 snprintf(fn, sizeof(fn), "digits/%d", num);
1483 } else if (num == 81) {
1484 snprintf(fn, sizeof(fn), "digits/%d", num);
1486 } else if (num == 88) {
1487 snprintf(fn, sizeof(fn), "digits/%d", num);
1489 } else if (num == 91) {
1490 snprintf(fn, sizeof(fn), "digits/%d", num);
1492 } else if (num == 98) {
1493 snprintf(fn, sizeof(fn), "digits/%d", num);
1495 } else if (num < 100) {
1496 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1497 num -= ((num / 10) * 10);
1500 if ((num / 100) > 1) {
1501 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1504 snprintf(fn, sizeof(fn), "digits/hundred");
1506 num -= ((num / 100) * 100);
1508 if (num < 1000000) { /* 1,000,000 */
1510 res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1515 if ((tempnum / 1000) < 2)
1516 snprintf(fn, sizeof(fn), "digits/thousand");
1517 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1518 snprintf(fn, sizeof(fn), "digits/thousands");
1520 if (num < 1000000000) { /* 1,000,000,000 */
1521 if ((num / 1000000) > 1)
1522 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1526 num = num % 1000000;
1527 if ((tempnum / 1000000) < 2)
1528 snprintf(fn, sizeof(fn), "digits/million");
1530 snprintf(fn, sizeof(fn), "digits/millions");
1533 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1540 if (!ast_streamfile(chan, fn, language)) {
1541 if ((audiofd > -1) && (ctrlfd > -1))
1542 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1544 res = ast_waitstream(chan, ints);
1546 ast_stopstream(chan);
1552 /*! \brief ast_say_number_full_nl: dutch syntax */
1553 /* New files: digits/nl-en
1555 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1562 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1563 while (!res && (num || playh )) {
1565 snprintf(fn, sizeof(fn), "digits/minus");
1566 if ( num > INT_MIN ) {
1572 snprintf(fn, sizeof(fn), "digits/hundred");
1574 } else if (num < 20) {
1575 snprintf(fn, sizeof(fn), "digits/%d", num);
1577 } else if (num < 100) {
1580 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1584 snprintf(fn, sizeof(fn), "digits/nl-en");
1586 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1591 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1593 num -= ((num / 100) * 100);
1595 if (num < 1000000) { /* 1,000,000 */
1596 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
1600 snprintf(fn, sizeof(fn), "digits/thousand");
1602 if (num < 1000000000) { /* 1,000,000,000 */
1603 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1606 num = num % 1000000;
1607 snprintf(fn, sizeof(fn), "digits/million");
1610 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1618 if (!ast_streamfile(chan, fn, language)) {
1619 if ((audiofd > -1) && (ctrlfd > -1))
1620 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1622 res = ast_waitstream(chan, ints);
1624 ast_stopstream(chan);
1630 /*! \brief ast_say_number_full_no: Norwegian syntax */
1632 In addition to American English, the following sounds are required: "and", "1N"
1634 static int ast_say_number_full_no(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1639 int cn = 1; /* +1 = commune; -1 = neuter */
1643 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1645 if (options && !strncasecmp(options, "n",1)) cn = -1;
1647 while (!res && (num || playh || playa )) {
1648 /* The grammar for Norwegian numbers is the same as for English except
1649 * for the following:
1650 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1651 * "and" before the last two digits, i.e. 2034 is "two thousand and
1652 * thirty-four" and 1000012 is "one million and twelve".
1655 snprintf(fn, sizeof(fn), "digits/minus");
1656 if ( num > INT_MIN ) {
1662 snprintf(fn, sizeof(fn), "digits/hundred");
1665 snprintf(fn, sizeof(fn), "digits/and");
1667 } else if (num == 1 && cn == -1) {
1668 snprintf(fn, sizeof(fn), "digits/1N");
1670 } else if (num < 20) {
1671 snprintf(fn, sizeof(fn), "digits/%d", num);
1673 } else if (num < 100) {
1674 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1675 num -= ((num / 10) * 10);
1676 } else if (num < 1000) {
1677 int hundreds = num / 100;
1679 snprintf(fn, sizeof(fn), "digits/1N");
1681 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1684 num -= 100 * hundreds;
1687 } else if (num < 1000000) {
1688 res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1691 snprintf(fn, sizeof(fn), "digits/thousand");
1693 if (num && num < 100)
1695 } else if (num < 1000000000) {
1696 int millions = num / 1000000;
1697 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1700 snprintf(fn, sizeof(fn), "digits/million");
1701 num = num % 1000000;
1702 if (num && num < 100)
1706 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1711 if (!ast_streamfile(chan, fn, language)) {
1712 if ((audiofd > -1) && (ctrlfd > -1))
1713 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1715 res = ast_waitstream(chan, ints);
1717 ast_stopstream(chan);
1724 char *separator_dziesiatek;
1728 char *dziesiatki[10];
1733 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1739 return odm->rzedy[rzad - 1][0];
1740 if ((i > 21 || i < 11) && i%10 > 1 && i%10 < 5)
1741 return odm->rzedy[rzad - 1][1];
1743 return odm->rzedy[rzad - 1][2];
1746 static char* pl_append(char* buffer, char* str)
1748 strcpy(buffer, str);
1749 buffer += strlen(str);
1753 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1755 char file_name[255] = "digits/";
1756 strcat(file_name, fn);
1758 ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
1759 if (!ast_streamfile(chan, file_name, language)) {
1760 if ((audiofd > -1) && (ctrlfd > -1))
1761 ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1763 ast_waitstream(chan, ints);
1765 ast_stopstream(chan);
1768 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1770 /* Initialise variables to allow compilation on Debian-stable, etc */
1780 if (i == 0 && rzad > 0) {
1784 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1788 m1000E6 = i % 1000000000;
1789 i1000E6 = i / 1000000000;
1791 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1793 m1000E3 = m1000E6 % 1000000;
1794 i1000E3 = m1000E6 / 1000000;
1796 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1798 m1000 = m1000E3 % 1000;
1799 i1000 = m1000E3 / 1000;
1801 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1807 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1809 if ( m100 > 0 && m100 <=9 ) {
1811 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1813 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1814 } else if (m100 % 10 == 0) {
1815 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1816 } else if (m100 <= 19 ) {
1817 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1818 } else if (m100 != 0) {
1819 if (odm->separator_dziesiatek[0]==' ') {
1820 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1821 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1825 b = pl_append(b, odm->dziesiatki[m100 / 10]);
1826 b = pl_append(b, odm->separator_dziesiatek);
1827 b = pl_append(b, odm->cyfry2[m100 % 10]);
1828 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1833 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1837 /* ast_say_number_full_pl: Polish syntax */
1838 static int ast_say_number_full_pl(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
1848 1000000000.2 miliardy
1849 1000000000.5 miliardow
1913 70m siedemdziesieciu
1925 90m dziewiedziesieciu
1927 and combinations of eg.: 20_1, 30m_3m, etc...
1931 char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1933 char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1935 char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1937 char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1939 char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1941 char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1943 char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1945 char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1947 char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1949 char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1951 char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1953 char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1955 char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}};
1957 /* Initialise variables to allow compilation on Debian-stable, etc */
1960 static odmiana *odmiana_nieosobowa = NULL;
1961 static odmiana *odmiana_meska = NULL;
1962 static odmiana *odmiana_zenska = NULL;
1964 if (odmiana_nieosobowa == NULL) {
1965 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
1967 odmiana_nieosobowa->separator_dziesiatek = " ";
1969 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1970 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1971 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1972 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1973 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1974 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1977 if (odmiana_zenska == NULL) {
1978 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
1980 odmiana_zenska->separator_dziesiatek = " ";
1982 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
1983 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
1984 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
1985 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
1986 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
1987 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
1990 if (odmiana_meska == NULL) {
1991 odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
1993 odmiana_meska->separator_dziesiatek = " ";
1995 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
1996 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
1997 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
1998 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
1999 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
2000 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
2004 if (strncasecmp(options, "f", 1) == 0)
2006 else if (strncasecmp(options, "m", 1) == 0)
2009 o = odmiana_nieosobowa;
2011 o = odmiana_nieosobowa;
2013 powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
2017 /* ast_say_number_full_pt: Portuguese syntax */
2018 /* Extra sounds needed: */
2019 /* For feminin all sound files end with F */
2020 /* 100E for 100+ something */
2021 /* 1000000S for plural */
2022 /* pt-e for 'and' */
2023 static int ast_say_number_full_pt(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2027 int mf = 1; /* +1 = male; -1 = female */
2031 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2033 if (options && !strncasecmp(options, "f",1))
2036 while (!res && num ) {
2038 snprintf(fn, sizeof(fn), "digits/minus");
2039 if ( num > INT_MIN ) {
2044 } else if (num < 20) {
2045 if ((num == 1 || num == 2) && (mf < 0))
2046 snprintf(fn, sizeof(fn), "digits/%dF", num);
2048 snprintf(fn, sizeof(fn), "digits/%d", num);
2050 } else if (num < 100) {
2051 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
2055 } else if (num < 1000) {
2057 snprintf(fn, sizeof(fn), "digits/100");
2059 snprintf(fn, sizeof(fn), "digits/100E");
2061 if (mf < 0 && num > 199)
2062 snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
2064 snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
2069 } else if (num < 1000000) {
2071 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
2075 snprintf(fn, sizeof(fn), "digits/1000");
2076 if ((num % 1000) && ((num % 1000) < 100 || !(num % 100)))
2079 } else if (num < 1000000000) {
2080 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
2084 snprintf(fn, sizeof(fn), "digits/1000000");
2086 snprintf(fn, sizeof(fn), "digits/1000000S");
2088 if ((num % 1000000) &&
2090 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
2091 /* no hundreds and below */
2092 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
2094 num = num % 1000000;
2096 /* number is too big */
2097 ast_log(LOG_WARNING, "Number '%d' is too big to say.", num);
2101 if (!ast_streamfile(chan, fn, language)) {
2102 if ((audiofd > -1) && (ctrlfd > -1))
2103 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2105 res = ast_waitstream(chan, ints);
2107 ast_stopstream(chan);
2109 if (!res && playh) {
2110 res = wait_file(chan, ints, "digits/pt-e", language);
2111 ast_stopstream(chan);
2118 /*! \brief ast_say_number_full_se: Swedish syntax */
2119 static int ast_say_number_full_se(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2124 int cn = 1; /* +1 = commune; -1 = neuter */
2126 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2127 if (options && !strncasecmp(options, "n",1)) cn = -1;
2129 while (!res && (num || playh)) {
2131 snprintf(fn, sizeof(fn), "digits/minus");
2132 if ( num > INT_MIN ) {
2138 snprintf(fn, sizeof(fn), "digits/hundred");
2140 } else if (num < 20) {
2141 snprintf(fn, sizeof(fn), "digits/%d", num);
2143 } else if (num < 100) {
2144 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2145 num -= ((num / 10) * 10);
2146 } else if (num == 1 && cn == -1) { /* En eller ett? */
2147 snprintf(fn, sizeof(fn), "digits/1N");
2151 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2153 num -= ((num / 100) * 100);
2155 if (num < 1000000) { /* 1,000,000 */
2156 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2161 snprintf(fn, sizeof(fn), "digits/thousand");
2163 if (num < 1000000000) { /* 1,000,000,000 */
2164 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2168 num = num % 1000000;
2169 snprintf(fn, sizeof(fn), "digits/million");
2172 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2179 if (!ast_streamfile(chan, fn, language)) {
2180 if ((audiofd > -1) && (ctrlfd > -1))
2181 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2183 res = ast_waitstream(chan, ints);
2184 ast_stopstream(chan);
2191 /*! \brief ast_say_number_full_tw: Taiwanese / Chinese syntax */
2192 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2198 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2200 while (!res && (num || playh)) {
2202 snprintf(fn, sizeof(fn), "digits/minus");
2203 if ( num > INT_MIN ) {
2209 snprintf(fn, sizeof(fn), "digits/hundred");
2211 } else if (num < 10) {
2212 snprintf(fn, sizeof(fn), "digits/%d", num);
2214 } else if (num < 100) {
2215 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2216 num -= ((num / 10) * 10);
2219 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2221 num -= ((num / 100) * 100);
2223 if (num < 1000000) { /* 1,000,000 */
2224 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
2228 snprintf(fn, sizeof(fn), "digits/thousand");
2230 if (num < 1000000000) { /* 1,000,000,000 */
2231 res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2234 num = num % 1000000;
2235 snprintf(fn, sizeof(fn), "digits/million");
2238 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2245 if (!ast_streamfile(chan, fn, language)) {
2246 if ((audiofd > -1) && (ctrlfd > -1))
2247 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2249 res = ast_waitstream(chan, ints);
2251 ast_stopstream(chan);
2258 /*! \brief determine last digits for thousands/millions (ru) */
2259 static int get_lastdigits_ru(int num) {
2262 } else if (num < 100) {
2263 return get_lastdigits_ru(num % 10);
2264 } else if (num < 1000) {
2265 return get_lastdigits_ru(num % 100);
2267 return 0; /* number too big */
2271 /*! \brief ast_say_number_full_ru: Russian syntax */
2272 /*! \brief additional files:
2273 n00.gsm (one hundred, two hundred, ...)
2276 thousands-i.gsm (tisyachi)
2277 million-a.gsm (milliona)
2283 where 'n' from 1 to 9
2285 static int ast_say_number_full_ru(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2291 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2293 while (!res && (num)) {
2295 snprintf(fn, sizeof(fn), "digits/minus");
2296 if ( num > INT_MIN ) {
2301 } else if (num < 20) {
2302 if (options && strlen(options) == 1 && num < 3) {
2303 snprintf(fn, sizeof(fn), "digits/%d%s", num, options);
2305 snprintf(fn, sizeof(fn), "digits/%d", num);
2308 } else if (num < 100) {
2309 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 10));
2311 } else if (num < 1000){
2312 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 100));
2314 } else if (num < 1000000) { /* 1,000,000 */
2315 lastdigits = get_lastdigits_ru(num / 1000);
2317 if (lastdigits < 3) {
2318 res = ast_say_number_full_ru(chan, num / 1000, ints, language, "f", audiofd, ctrlfd);
2320 res = ast_say_number_full_ru(chan, num / 1000, ints, language, NULL, audiofd, ctrlfd);
2324 if (lastdigits == 1) {
2325 snprintf(fn, sizeof(fn), "digits/thousand");
2326 } else if (lastdigits > 1 && lastdigits < 5) {
2327 snprintf(fn, sizeof(fn), "digits/thousands-i");
2329 snprintf(fn, sizeof(fn), "digits/thousands");
2332 } else if (num < 1000000000) { /* 1,000,000,000 */
2333 lastdigits = get_lastdigits_ru(num / 1000000);
2335 res = ast_say_number_full_ru(chan, num / 1000000, ints, language, NULL, audiofd, ctrlfd);
2338 if (lastdigits == 1) {
2339 snprintf(fn, sizeof(fn), "digits/million");
2340 } else if (lastdigits > 1 && lastdigits < 5) {
2341 snprintf(fn, sizeof(fn), "digits/million-a");
2343 snprintf(fn, sizeof(fn), "digits/millions");
2348 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2352 if (!ast_streamfile(chan, fn, language)) {
2353 if ((audiofd > -1) && (ctrlfd > -1))
2354 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2356 res = ast_waitstream(chan, ints);
2358 ast_stopstream(chan);
2365 /*! \brief ast_say_enumeration_full: call language-specific functions */
2366 /* Called from AGI */
2367 static int say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2369 if (!strcasecmp(language,"en") ) { /* English syntax */
2370 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2371 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
2372 return(ast_say_enumeration_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
2373 } else if (!strcasecmp(language, "de") ) { /* German syntax */
2374 return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2377 /* Default to english */
2378 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2381 /*! \brief ast_say_enumeration_full_en: English syntax */
2382 /* This is the default syntax, if no other syntax defined in this file is used */
2383 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2388 while (!res && num) {
2390 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2391 if ( num > INT_MIN ) {
2396 } else if (num < 20) {
2397 snprintf(fn, sizeof(fn), "digits/h-%d", num);
2399 } else if (num < 100) {
2400 int tens = num / 10;
2403 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2405 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2407 } else if (num < 1000) {
2408 int hundreds = num / 100;
2410 if (hundreds > 1 || t == 1) {
2411 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2416 snprintf(fn, sizeof(fn), "digits/hundred");
2418 snprintf(fn, sizeof(fn), "digits/h-hundred");
2420 } else if (num < 1000000) {
2421 int thousands = num / 1000;
2423 if (thousands > 1 || t == 1) {
2424 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2429 snprintf(fn, sizeof(fn), "digits/thousand");
2431 snprintf(fn, sizeof(fn), "digits/h-thousand");
2434 } else if (num < 1000000000) {
2435 int millions = num / 1000000;
2436 num = num % 1000000;
2438 res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2442 snprintf(fn, sizeof(fn), "digits/million");
2444 snprintf(fn, sizeof(fn), "digits/h-million");
2446 } else if (num < INT_MAX) {
2447 int billions = num / 1000000000;
2448 num = num % 1000000000;
2450 res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2454 snprintf(fn, sizeof(fn), "digits/billion");
2456 snprintf(fn, sizeof(fn), "digits/h-billion");
2458 } else if (num == INT_MAX) {
2459 snprintf(fn, sizeof(fn), "digits/h-last");
2463 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2468 if (!ast_streamfile(chan, fn, language)) {
2469 if ((audiofd > -1) && (ctrlfd > -1)) {
2470 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2472 res = ast_waitstream(chan, ints);
2475 ast_stopstream(chan);
2481 /*! \brief ast_say_enumeration_full_da: Danish syntax */
2482 static int ast_say_enumeration_full_da(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2484 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2486 char fn[256] = "", fna[256] = "";
2489 if (options && !strncasecmp(options, "f",1)) {
2491 } else if (options && !strncasecmp(options, "n",1)) {
2498 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2500 while (!res && num) {
2502 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2503 if ( num > INT_MIN ) {
2508 } else if (num < 100 && t) {
2509 snprintf(fn, sizeof(fn), "digits/and");
2511 } else if (num < 20) {
2512 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2514 } else if (num < 100) {
2515 int ones = num % 10;
2517 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2520 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2523 } else if (num == 100 && t == 0) {
2524 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2526 } else if (num < 1000) {
2527 int hundreds = num / 100;
2529 if (hundreds == 1) {
2530 snprintf(fn, sizeof(fn), "digits/1N");
2532 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2535 snprintf(fna, sizeof(fna), "digits/hundred");
2537 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2540 } else if (num < 1000000) {
2541 int thousands = num / 1000;
2543 if (thousands == 1) {
2545 snprintf(fn, sizeof(fn), "digits/1N");
2546 snprintf(fna, sizeof(fna), "digits/thousand");
2549 snprintf(fn, sizeof(fn), "digits/1N");
2550 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2552 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2556 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2561 snprintf(fn, sizeof(fn), "digits/thousand");
2563 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2567 } else if (num < 1000000000) {
2568 int millions = num / 1000000;
2569 num = num % 1000000;
2570 if (millions == 1) {
2572 snprintf(fn, sizeof(fn), "digits/1F");
2573 snprintf(fna, sizeof(fna), "digits/million");
2575 snprintf(fn, sizeof(fn), "digits/1N");
2576 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2579 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2584 snprintf(fn, sizeof(fn), "digits/millions");
2586 snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2590 } else if (num < INT_MAX) {
2591 int billions = num / 1000000000;
2592 num = num % 1000000000;
2593 if (billions == 1) {
2595 snprintf(fn, sizeof(fn), "digits/1F");
2596 snprintf(fna, sizeof(fna), "digits/milliard");
2598 snprintf(fn, sizeof(fn), "digits/1N");
2599 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2602 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2606 snprintf(fn, sizeof(fna), "digits/milliards");
2608 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2612 } else if (num == INT_MAX) {
2613 snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2617 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2622 if (!ast_streamfile(chan, fn, language)) {
2623 if ((audiofd > -1) && (ctrlfd > -1))
2624 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2626 res = ast_waitstream(chan, ints);
2628 ast_stopstream(chan);
2630 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2631 if ((audiofd > -1) && (ctrlfd > -1)) {
2632 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2634 res = ast_waitstream(chan, ints);
2637 ast_stopstream(chan);
2645 /*! \brief ast_say_enumeration_full_de: German syntax */
2646 static int ast_say_enumeration_full_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2648 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2650 char fn[256] = "", fna[256] = "";
2653 if (options && !strncasecmp(options, "f",1)) {
2655 } else if (options && !strncasecmp(options, "n",1)) {
2662 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2664 while (!res && num) {
2666 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2667 if ( num > INT_MIN ) {
2672 } else if (num < 100 && t) {
2673 snprintf(fn, sizeof(fn), "digits/and");
2675 } else if (num < 20) {
2676 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2678 } else if (num < 100) {
2679 int ones = num % 10;
2681 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2684 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2687 } else if (num == 100 && t == 0) {
2688 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2690 } else if (num < 1000) {
2691 int hundreds = num / 100;
2693 if (hundreds == 1) {
2694 snprintf(fn, sizeof(fn), "digits/1N");
2696 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2699 snprintf(fna, sizeof(fna), "digits/hundred");
2701 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2704 } else if (num < 1000000) {
2705 int thousands = num / 1000;
2707 if (thousands == 1) {
2709 snprintf(fn, sizeof(fn), "digits/1N");
2710 snprintf(fna, sizeof(fna), "digits/thousand");
2713 snprintf(fn, sizeof(fn), "digits/1N");
2714 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2716 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2720 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2725 snprintf(fn, sizeof(fn), "digits/thousand");
2727 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2731 } else if (num < 1000000000) {
2732 int millions = num / 1000000;
2733 num = num % 1000000;
2734 if (millions == 1) {
2736 snprintf(fn, sizeof(fn), "digits/1F");
2737 snprintf(fna, sizeof(fna), "digits/million");
2739 snprintf(fn, sizeof(fn), "digits/1N");
2740 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2743 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2748 snprintf(fn, sizeof(fn), "digits/millions");
2750 snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2754 } else if (num < INT_MAX) {
2755 int billions = num / 1000000000;
2756 num = num % 1000000000;
2757 if (billions == 1) {
2759 snprintf(fn, sizeof(fn), "digits/1F");