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 * 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr)
25 * George Konstantoulakis <gkon@inaccessnetworks.com>
28 #include <sys/types.h>
31 #include <netinet/in.h>
38 #include <iso/limits_iso.h>
43 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
45 #include "asterisk/file.h"
46 #include "asterisk/channel.h"
47 #include "asterisk/logger.h"
48 #include "asterisk/options.h"
49 #include "asterisk/say.h"
50 #include "asterisk/lock.h"
51 #include "asterisk/localtime.h"
52 #include "asterisk/utils.h"
54 /* Forward declaration */
55 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
57 int ast_say_character_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
75 fn = "letters/exclaimation-point";
81 fn = "letters/dollar";
90 fn = "letters/equals";
111 strcpy(fnbuf, "digits/X");
117 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
118 strcpy(fnbuf, "letters/X");
122 res = ast_streamfile(chan, fn, lang);
124 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
125 ast_stopstream(chan);
132 int ast_say_character_str(struct ast_channel *chan, const char *str, const char *ints, const char *lang)
134 return ast_say_character_str_full(chan, str, ints, lang, -1, -1);
137 int ast_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 int ast_say_phonetic_str(struct ast_channel *chan, const char *str, const char *ints, const char *lang)
213 return ast_say_phonetic_str_full(chan, str, ints, lang, -1, -1);
216 int ast_say_digit_str_full(struct ast_channel *chan, const char *str, const char *ints, const char *lang, int audiofd, int ctrlfd)
223 while (str[num] && !res) {
245 strcpy(fnbuf, "digits/X");
251 res = ast_streamfile(chan, fn, lang);
253 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
254 ast_stopstream(chan);
262 int ast_say_digit_str(struct ast_channel *chan, const char *str, const char *ints, const char *lang)
264 return ast_say_digit_str_full(chan, str, ints, lang, -1, -1);
267 int ast_say_digits_full(struct ast_channel *chan, int num, const char *ints, const char *lang, int audiofd, int ctrlfd)
271 snprintf(fn2, sizeof(fn2), "%d", num);
272 return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
275 int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
277 return ast_say_digits_full(chan, num, ints, lang, -1, -1);
280 /* Forward declarations */
281 /* Syntaxes supported, not really language codes.
285 en_GB - English (British)
286 es - Spanish, Mexican
299 For Some languages the numbers differ for gender and plural
300 Use the option argument 'f' for female, 'm' for male and 'n' for neuter in languages like Portuguese, French, Spanish and German.
301 use the option argument 'c' is for commune and 'n' for neuter gender in nordic languages like Danish, Swedish and Norwegian.
302 use the option argument 'p' for plural enumerations like in German
304 Date/Time functions currently have less languages supported than saynumber().
306 Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
308 See contrib/i18n.testsuite.conf for some examples of the different syntaxes
310 Portuguese sound files needed for Time/Date functions:
320 Spanish sound files needed for Time/Date functions:
324 Italian sound files needed for Time/Date functions:
330 /* Forward declarations of language specific variants of ast_say_number_full */
331 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
332 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);
333 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);
334 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);
335 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
336 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);
337 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);
338 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);
339 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
340 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
341 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);
342 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);
343 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);
344 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);
345 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
346 static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
347 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);
349 /* Forward declarations of language specific variants of ast_say_enumeration_full */
350 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
351 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);
352 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);
354 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
355 static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
356 static int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
357 static int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
358 static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
359 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
360 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
361 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
363 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);
364 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);
365 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);
366 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);
367 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);
368 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);
369 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);
370 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);
371 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);
372 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);
373 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);
375 static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
376 static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
377 static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
378 static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
379 static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
380 static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
381 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
383 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
384 static int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
385 static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
386 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
387 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
388 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
389 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
391 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
392 static int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
393 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
395 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang)
398 if ((res = ast_streamfile(chan, file, lang)))
399 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
401 res = ast_waitstream(chan, ints);
405 /*! \brief ast_say_number_full: call language-specific functions */
406 /* Called from AGI */
407 int ast_say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
409 if (!strcasecmp(language,"en") ) { /* English syntax */
410 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
411 } else if (!strcasecmp(language, "cz") ) { /* Czech syntax */
412 return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd));
413 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
414 return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
415 } else if (!strcasecmp(language, "de") ) { /* German syntax */
416 return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
417 } else if (!strcasecmp(language, "en_GB") ) { /* British syntax */
418 return(ast_say_number_full_en_GB(chan, num, ints, language, audiofd, ctrlfd));
419 } else if (!strcasecmp(language, "no") ) { /* Norwegian syntax */
420 return(ast_say_number_full_no(chan, num, ints, language, options, audiofd, ctrlfd));
421 } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) { /* Spanish syntax */
422 return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd));
423 } else if (!strcasecmp(language, "fr") ) { /* French syntax */
424 return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd));
425 } else if (!strcasecmp(language, "he") ) { /* Hebrew syntax */
426 return(ast_say_number_full_he(chan, num, ints, language, options, audiofd, ctrlfd));
427 } else if (!strcasecmp(language, "it") ) { /* Italian syntax */
428 return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd));
429 } else if (!strcasecmp(language, "nl") ) { /* Dutch syntax */
430 return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd));
431 } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */
432 return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd));
433 } else if (!strcasecmp(language, "pt") ) { /* Portuguese syntax */
434 return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd));
435 } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */
436 return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd));
437 } else if (!strcasecmp(language, "tw")) { /* Taiwanese syntax */
438 return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd));
439 } else if (!strcasecmp(language, "gr") ) { /* Greek syntax */
440 return(ast_say_number_full_gr(chan, num, ints, language, audiofd, ctrlfd));
441 } else if (!strcasecmp(language, "ru") ) { /* Russian syntax */
442 return(ast_say_number_full_ru(chan, num, ints, language, options, audiofd, ctrlfd));
445 /* Default to english */
446 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
449 /*! \brief ast_say_number: call language-specific functions without file descriptors */
450 int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
452 return(ast_say_number_full(chan, num, ints, language, options, -1, -1));
455 /*! \brief ast_say_number_full_en: English syntax */
456 /* This is the default syntax, if no other syntax defined in this file is used */
457 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
463 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
465 while(!res && (num || playh)) {
467 snprintf(fn, sizeof(fn), "digits/minus");
468 if ( num > INT_MIN ) {
474 snprintf(fn, sizeof(fn), "digits/hundred");
476 } else if (num < 20) {
477 snprintf(fn, sizeof(fn), "digits/%d", num);
479 } else if (num < 100) {
480 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
481 num -= ((num / 10) * 10);
484 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
486 num -= ((num / 100) * 100);
488 if (num < 1000000) { /* 1,000,000 */
489 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
493 snprintf(fn, sizeof(fn), "digits/thousand");
495 if (num < 1000000000) { /* 1,000,000,000 */
496 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
500 snprintf(fn, sizeof(fn), "digits/million");
502 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
509 if(!ast_streamfile(chan, fn, language)) {
510 if ((audiofd > -1) && (ctrlfd > -1))
511 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
513 res = ast_waitstream(chan, ints);
515 ast_stopstream(chan);
521 static int exp10_int(int power)
524 for (x=0;x<power;x++)
529 /*! \brief ast_say_number_full_cz: Czech syntax */
531 * 1m,2m - gender male
532 * 1w,2w - gender female
536 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set
538 * for each number 10^(3n + 3) exist 3 files represented as:
539 * 1 tousand = jeden tisic = 1_E3
540 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
541 * 5,6,... tousands = pet,sest,... tisic = 5_E3
547 * tousand, milion are gender male, so 1 and 2 is 1m 2m
548 * miliard is gender female, so 1 and 2 is 1w 2w
550 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)
560 /* options - w = woman, m = man, n = neutral. Defaultl is woman */
565 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
567 while(!res && (num || playh)) {
569 snprintf(fn, sizeof(fn), "digits/minus");
570 if ( num > INT_MIN ) {
575 } else if (num < 3 ) {
576 snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]);
579 } else if (num < 20) {
580 snprintf(fn, sizeof(fn), "digits/%d",num);
583 } else if (num < 100) {
584 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
585 num -= ((num / 10) * 10);
586 } else if (num < 1000) {
587 hundered = num / 100;
588 if ( hundered == 1 ) {
589 snprintf(fn, sizeof(fn), "digits/1sto");
590 } else if ( hundered == 2 ) {
591 snprintf(fn, sizeof(fn), "digits/2ste");
593 res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd);
596 if (hundered == 3 || hundered == 4) {
597 snprintf(fn, sizeof(fn), "digits/sta");
598 } else if ( hundered > 4 ) {
599 snprintf(fn, sizeof(fn), "digits/set");
602 num -= (hundered * 100);
603 } else { /* num > 1000 */
604 length = (int)log10(num)+1;
605 while ( (length % 3 ) != 1 ) {
608 left = num / (exp10_int(length-1));
611 case 9: options = "w"; /* 1,000,000,000 gender female */
613 default : options = "m"; /* others are male */
616 if ( left > 1 ) { /* we dont say "one thousand" but only thousand */
617 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd);
621 if ( left >= 5 ) { /* >= 5 have the same declesion */
622 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1);
623 } else if ( left >= 2 && left <= 4 ) {
624 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1);
625 } else { /* left == 1 */
626 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1);
628 num -= left * (exp10_int(length-1));
631 if(!ast_streamfile(chan, fn, language)) {
632 if ((audiofd > -1) && (ctrlfd > -1)) {
633 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
635 res = ast_waitstream(chan, ints);
638 ast_stopstream(chan);
644 /*! \brief ast_say_number_full_da: Danish syntax */
646 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and"
648 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)
653 int cn = 1; /* +1 = commune; -1 = neuter */
656 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
658 if (options && !strncasecmp(options, "n",1)) cn = -1;
660 while(!res && (num || playh || playa )) {
661 /* The grammar for Danish numbers is the same as for English except
663 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1")
664 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
665 * "one-and twenty" and 68 is "eight-and sixty".
666 * - "million" is different in singular and plural form
667 * - numbers > 1000 with zero as the third digit from last have an
668 * "and" before the last two digits, i.e. 2034 is "two thousand and
669 * four-and thirty" and 1000012 is "one million and twelve".
672 snprintf(fn, sizeof(fn), "digits/minus");
673 if ( num > INT_MIN ) {
679 snprintf(fn, sizeof(fn), "digits/hundred");
682 snprintf(fn, sizeof(fn), "digits/and");
684 } else if (num == 1 && cn == -1) {
685 snprintf(fn, sizeof(fn), "digits/1N");
687 } else if (num < 20) {
688 snprintf(fn, sizeof(fn), "digits/%d", num);
690 } else if (num < 100) {
693 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
696 snprintf(fn, sizeof(fn), "digits/%d", num);
701 int hundreds = num / 100;
703 snprintf(fn, sizeof(fn), "digits/1N");
705 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
708 num -= 100 * hundreds;
714 res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
718 snprintf(fn, sizeof(fn), "digits/thousand");
720 if (num < 1000000000) {
721 int millions = num / 1000000;
722 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
726 snprintf(fn, sizeof(fn), "digits/million");
728 snprintf(fn, sizeof(fn), "digits/millions");
731 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
735 if (num && num < 100)
740 if(!ast_streamfile(chan, fn, language)) {
741 if ((audiofd > -1) && (ctrlfd > -1))
742 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
744 res = ast_waitstream(chan, ints);
746 ast_stopstream(chan);
752 /*! \brief ast_say_number_full_de: German syntax */
754 In addition to English, the following sounds are required:
756 "1-and" through "9-and"
759 NB "1" is recorded as 'eins'
761 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)
764 int mf = 1; /* +1 = male and neuter; -1 = female */
768 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
770 if (options && (!strncasecmp(options, "f",1)))
774 /* The grammar for German numbers is the same as for English except
776 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
777 * "one-and twenty" and 68 is "eight-and sixty".
778 * - "one" varies according to gender
779 * - 100 is 'hundert', however all other instances are 'ein hundert'
780 * - 1000 is 'tausend', however all other instances are 'ein tausend'
781 * - 1000000 is always 'eine million'
782 * - "million" is different in singular and plural form
785 snprintf(fn, sizeof(fn), "digits/minus");
786 if ( num > INT_MIN ) {
791 } else if (num < 100 && t) {
792 snprintf(fn, sizeof(fn), "digits/and");
794 } else if (num == 1 && mf == -1) {
795 snprintf(fn, sizeof(fn), "digits/%dF", num);
797 } else if (num < 20) {
798 snprintf(fn, sizeof(fn), "digits/%d", num);
800 } else if (num < 100) {
803 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
806 snprintf(fn, sizeof(fn), "digits/%d", num);
809 } else if (num == 100 && t == 0) {
810 snprintf(fn, sizeof(fn), "digits/hundred");
812 } else if (num < 1000) {
813 int hundreds = num / 100;
816 snprintf(fn, sizeof(fn), "digits/1N");
818 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
820 snprintf(fna, sizeof(fna), "digits/hundred");
822 } else if (num == 1000 && t == 0) {
823 snprintf(fn, sizeof(fn), "digits/thousand");
825 } else if (num < 1000000) {
826 int thousands = num / 1000;
829 if (thousands == 1) {
830 snprintf(fn, sizeof(fn), "digits/1N");
831 snprintf(fna, sizeof(fna), "digits/thousand");
833 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
836 snprintf(fn, sizeof(fn), "digits/thousand");
838 } else if (num < 1000000000) {
839 int millions = num / 1000000;
843 snprintf(fn, sizeof(fn), "digits/1F");
844 snprintf(fna, sizeof(fna), "digits/million");
846 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
849 snprintf(fn, sizeof(fn), "digits/millions");
851 } else if (num <= INT_MAX) {
852 int billions = num / 1000000000;
853 num = num % 1000000000;
856 snprintf(fn, sizeof(fn), "digits/1F");
857 snprintf(fna, sizeof(fna), "digits/milliard");
859 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
863 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)
951 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
956 if(!ast_streamfile(chan, fn, language)) {
957 if ((audiofd > -1) && (ctrlfd > -1))
958 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
960 res = ast_waitstream(chan, ints);
962 ast_stopstream(chan);
968 /*! \brief ast_say_number_full_es: Spanish syntax */
970 Requires a few new audios:
971 1F.gsm: feminine 'una'
972 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
974 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)
978 int mf = 0; /* +1 = male; -1 = female */
981 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
984 if (!strncasecmp(options, "f",1))
986 else if (!strncasecmp(options, "m", 1))
990 while (!res && num) {
992 snprintf(fn, sizeof(fn), "digits/minus");
993 if ( num > INT_MIN ) {
999 snprintf(fn, sizeof(fn), "digits/and");
1001 } else if (num == 1) {
1003 snprintf(fn, sizeof(fn), "digits/%dF", num);
1005 snprintf(fn, sizeof(fn), "digits/%dM", num);
1007 snprintf(fn, sizeof(fn), "digits/%d", num);
1009 } else if (num < 31) {
1010 snprintf(fn, sizeof(fn), "digits/%d", num);
1012 } else if (num < 100) {
1013 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1014 num -= ((num/10)*10);
1017 } else if (num == 100) {
1018 snprintf(fn, sizeof(fn), "digits/100");
1020 } else if (num < 200) {
1021 snprintf(fn, sizeof(fn), "digits/100-and");
1025 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
1026 num -= ((num/100)*100);
1027 } else if (num < 2000) {
1029 snprintf(fn, sizeof(fn), "digits/thousand");
1031 if (num < 1000000) {
1032 res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1036 snprintf(fn, sizeof(fn), "digits/thousand");
1038 if (num < 2147483640) {
1039 if ((num/1000000) == 1) {
1040 res = ast_say_number_full_es(chan, num / 1000000, ints, language, "M", audiofd, ctrlfd);
1043 snprintf(fn, sizeof(fn), "digits/million");
1045 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1048 snprintf(fn, sizeof(fn), "digits/millions");
1050 num = num % 1000000;
1052 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1060 if(!ast_streamfile(chan, fn, language)) {
1061 if ((audiofd > -1) && (ctrlfd > -1))
1062 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1064 res = ast_waitstream(chan, ints);
1066 ast_stopstream(chan);
1074 /*! \brief ast_say_number_full_fr: French syntax */
1075 /* Extra sounds needed:
1078 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)
1083 int mf = 1; /* +1 = male; -1 = female */
1086 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1088 if (options && !strncasecmp(options, "f",1))
1091 while(!res && (num || playh || playa)) {
1093 snprintf(fn, sizeof(fn), "digits/minus");
1094 if ( num > INT_MIN ) {
1100 snprintf(fn, sizeof(fn), "digits/hundred");
1103 snprintf(fn, sizeof(fn), "digits/et");
1105 } else if (num == 1) {
1107 snprintf(fn, sizeof(fn), "digits/%dF", num);
1109 snprintf(fn, sizeof(fn), "digits/%d", num);
1111 } else if (num < 21) {
1112 snprintf(fn, sizeof(fn), "digits/%d", num);
1114 } else if (num < 70) {
1115 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1116 if ((num % 10) == 1) playa++;
1118 } else if (num < 80) {
1119 snprintf(fn, sizeof(fn), "digits/60");
1120 if ((num % 10) == 1) playa++;
1122 } else if (num < 100) {
1123 snprintf(fn, sizeof(fn), "digits/80");
1125 } else if (num < 200) {
1126 snprintf(fn, sizeof(fn), "digits/hundred");
1128 } else if (num < 1000) {
1129 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1132 } else if (num < 2000) {
1133 snprintf(fn, sizeof(fn), "digits/thousand");
1135 } else if (num < 1000000) {
1136 res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1139 snprintf(fn, sizeof(fn), "digits/thousand");
1141 } else if (num < 1000000000) {
1142 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1145 snprintf(fn, sizeof(fn), "digits/million");
1146 num = num % 1000000;
1148 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1152 if(!ast_streamfile(chan, fn, language)) {
1153 if ((audiofd > -1) && (ctrlfd > -1))
1154 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1156 res = ast_waitstream(chan, ints);
1158 ast_stopstream(chan);
1166 /*! \brief ast_say_number_full_he: Hebrew syntax */
1167 /* Extra sounds needed:
1171 2thousands: 2 thousand
1172 thousands: plural of 'thousand'
1173 3sF 'Smichut forms (female)
1180 3s 'Smichut' forms (male)
1197 TODO: 've' should sometimed be 'hu':
1198 * before 'shtaym' (2, F)
1199 * before 'shnaym' (2, M)
1200 * before 'shlosha' (3, M)
1201 * before 'shmone' (8, M)
1202 * before 'shlosim' (30)
1203 * before 'shmonim' (80)
1209 #define SAY_NUM_BUF_SIZE 256
1210 static int ast_say_number_full_he(struct ast_channel *chan, int num,
1211 const char *ints, const char *language, const char *options,
1212 int audiofd, int ctrlfd)
1215 int state = 0; /* no need to save anything */
1216 int mf = 1; /* +1 = Masculin; -1 = Feminin */
1217 char fn[SAY_NUM_BUF_SIZE] = "";
1218 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: started. "
1219 "num: %d, options=\"%s\"\n",
1223 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1225 if (options && !strncasecmp(options, "f",1))
1228 /* Do we have work to do? */
1229 while(!res && (num || (state>0) )) {
1230 /* first type of work: play a second sound. In this loop
1231 * we can only play one sound file at a time. Thus playing
1232 * a second one requires repeating the loop just for the
1233 * second file. The variable 'state' remembers where we were.
1234 * state==0 is the normal mode and it means that we continue
1235 * to check if the number num has yet anything left.
1237 ast_verbose(VERBOSE_PREFIX_3 "ast_say_digits_full: num: %d, "
1238 "state=%d, options=\"%s\", mf=%d\n",
1239 num, state, options, mf
1242 snprintf(fn, sizeof(fn), "digits/hundred");
1244 } else if (state==2) {
1245 snprintf(fn, sizeof(fn), "digits/ve");
1247 } else if (state==3) {
1248 snprintf(fn, sizeof(fn), "digits/thousands");
1250 } else if (num <21) {
1252 snprintf(fn, sizeof(fn), "digits/%dF", num);
1254 snprintf(fn, sizeof(fn), "digits/%d", num);
1256 } else if (num < 100) {
1257 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1260 } else if (num < 200) {
1261 snprintf(fn, sizeof(fn), "digits/hundred");
1263 } else if (num < 300) {
1264 snprintf(fn, sizeof(fn), "digits/hundred");
1266 } else if (num < 1000) {
1267 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1270 } else if (num < 2000) {
1271 snprintf(fn, sizeof(fn), "digits/thousand");
1273 } else if (num < 3000) {
1274 snprintf(fn, sizeof(fn), "digits/2thousand");
1277 } else if (num < 20000) {
1278 snprintf(fn, sizeof(fn), "digits/%ds",(num/1000));
1281 } else if (num < 1000000) {
1282 res = ast_say_number_full_he(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1285 snprintf(fn, sizeof(fn), "digits/thousand");
1287 } else if (num < 1000000000) {
1288 res = ast_say_number_full_he(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1291 snprintf(fn, sizeof(fn), "digits/million");
1292 num = num % 1000000;
1294 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1298 if(!ast_streamfile(chan, fn, language)) {
1299 if ((audiofd > -1) && (ctrlfd > -1))
1300 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1302 res = ast_waitstream(chan, ints);
1304 ast_stopstream(chan);
1310 /*! \brief ast_say_number_full_it: Italian */
1311 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1319 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1324 Like english, numbers up to 20 are a single 'word', and others
1325 compound, but with exceptions.
1326 For example 21 is not twenty-one, but there is a single word in 'it'.
1327 Idem for 28 (ie when a the 2nd part of a compund number
1328 starts with a vowel)
1330 There are exceptions also for hundred, thousand and million.
1331 In english 100 = one hundred, 200 is two hundred.
1332 In italian 100 = cento , like to say hundred (without one),
1333 200 and more are like english.
1335 Same applies for thousand:
1336 1000 is one thousand in en, 2000 is two thousand.
1337 In it we have 1000 = mille , 2000 = 2 mila
1339 For million(s) we use the plural, if more than one
1340 Also, one million is abbreviated in it, like on-million,
1341 or 'un milione', not 'uno milione'.
1342 So the right file is provided.
1345 while(!res && (num || playh)) {
1347 snprintf(fn, sizeof(fn), "digits/minus");
1348 if ( num > INT_MIN ) {
1354 snprintf(fn, sizeof(fn), "digits/hundred");
1356 } else if (num < 20) {
1357 snprintf(fn, sizeof(fn), "digits/%d", num);
1359 } else if (num == 21) {
1360 snprintf(fn, sizeof(fn), "digits/%d", num);
1362 } else if (num == 28) {
1363 snprintf(fn, sizeof(fn), "digits/%d", num);
1365 } else if (num == 31) {
1366 snprintf(fn, sizeof(fn), "digits/%d", num);
1368 } else if (num == 38) {
1369 snprintf(fn, sizeof(fn), "digits/%d", num);
1371 } else if (num == 41) {
1372 snprintf(fn, sizeof(fn), "digits/%d", num);
1374 } else if (num == 48) {
1375 snprintf(fn, sizeof(fn), "digits/%d", num);
1377 } else if (num == 51) {
1378 snprintf(fn, sizeof(fn), "digits/%d", num);
1380 } else if (num == 58) {
1381 snprintf(fn, sizeof(fn), "digits/%d", num);
1383 } else if (num == 61) {
1384 snprintf(fn, sizeof(fn), "digits/%d", num);
1386 } else if (num == 68) {
1387 snprintf(fn, sizeof(fn), "digits/%d", num);
1389 } else if (num == 71) {
1390 snprintf(fn, sizeof(fn), "digits/%d", num);
1392 } else if (num == 78) {
1393 snprintf(fn, sizeof(fn), "digits/%d", num);
1395 } else if (num == 81) {
1396 snprintf(fn, sizeof(fn), "digits/%d", num);
1398 } else if (num == 88) {
1399 snprintf(fn, sizeof(fn), "digits/%d", num);
1401 } else if (num == 91) {
1402 snprintf(fn, sizeof(fn), "digits/%d", num);
1404 } else if (num == 98) {
1405 snprintf(fn, sizeof(fn), "digits/%d", num);
1407 } else if (num < 100) {
1408 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1409 num -= ((num / 10) * 10);
1412 if ((num / 100) > 1) {
1413 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1416 snprintf(fn, sizeof(fn), "digits/hundred");
1418 num -= ((num / 100) * 100);
1420 if (num < 1000000) { /* 1,000,000 */
1422 res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1427 if ((tempnum / 1000) < 2)
1428 snprintf(fn, sizeof(fn), "digits/thousand");
1429 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1430 snprintf(fn, sizeof(fn), "digits/thousands");
1432 if (num < 1000000000) { /* 1,000,000,000 */
1433 if ((num / 1000000) > 1)
1434 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1438 num = num % 1000000;
1439 if ((tempnum / 1000000) < 2)
1440 snprintf(fn, sizeof(fn), "digits/million");
1442 snprintf(fn, sizeof(fn), "digits/millions");
1444 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1451 if(!ast_streamfile(chan, fn, language)) {
1452 if ((audiofd > -1) && (ctrlfd > -1))
1453 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1455 res = ast_waitstream(chan, ints);
1457 ast_stopstream(chan);
1463 /*! \brief ast_say_number_full_nl: dutch syntax */
1464 /* New files: digits/nl-en
1466 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1473 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1474 while (!res && (num || playh )) {
1476 snprintf(fn, sizeof(fn), "digits/minus");
1477 if ( num > INT_MIN ) {
1483 snprintf(fn, sizeof(fn), "digits/hundred");
1485 } else if (num < 20) {
1486 snprintf(fn, sizeof(fn), "digits/%d", num);
1488 } else if (num < 100) {
1491 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1495 snprintf(fn, sizeof(fn), "digits/nl-en");
1497 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1502 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1504 num -= ((num / 100) * 100);
1506 if (num < 1000000) { /* 1,000,000 */
1507 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
1511 snprintf(fn, sizeof(fn), "digits/thousand");
1513 if (num < 1000000000) { /* 1,000,000,000 */
1514 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1517 num = num % 1000000;
1518 snprintf(fn, sizeof(fn), "digits/million");
1520 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1528 if(!ast_streamfile(chan, fn, language)) {
1529 if ((audiofd > -1) && (ctrlfd > -1))
1530 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1532 res = ast_waitstream(chan, ints);
1534 ast_stopstream(chan);
1540 /*! \brief ast_say_number_full_no: Norwegian syntax */
1542 In addition to American English, the following sounds are required: "and", "1N"
1544 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)
1549 int cn = 1; /* +1 = commune; -1 = neuter */
1553 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1555 if (options && !strncasecmp(options, "n",1)) cn = -1;
1557 while(!res && (num || playh || playa )) {
1558 /* The grammar for Norwegian numbers is the same as for English except
1559 * for the following:
1560 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1561 * "and" before the last two digits, i.e. 2034 is "two thousand and
1562 * thirty-four" and 1000012 is "one million and twelve".
1565 snprintf(fn, sizeof(fn), "digits/minus");
1566 if ( num > INT_MIN ) {
1572 snprintf(fn, sizeof(fn), "digits/hundred");
1575 snprintf(fn, sizeof(fn), "digits/and");
1577 } else if (num == 1 && cn == -1) {
1578 snprintf(fn, sizeof(fn), "digits/1N");
1580 } else if (num < 20) {
1581 snprintf(fn, sizeof(fn), "digits/%d", num);
1583 } else if (num < 100) {
1584 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1585 num -= ((num / 10) * 10);
1586 } else if (num < 1000) {
1587 int hundreds = num / 100;
1589 snprintf(fn, sizeof(fn), "digits/1N");
1591 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1594 num -= 100 * hundreds;
1597 } else if (num < 1000000) {
1598 res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1601 snprintf(fn, sizeof(fn), "digits/thousand");
1603 if (num && num < 100)
1605 } else if (num < 1000000000) {
1606 int millions = num / 1000000;
1607 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1610 snprintf(fn, sizeof(fn), "digits/million");
1611 num = num % 1000000;
1612 if (num && num < 100)
1615 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1620 if(!ast_streamfile(chan, fn, language)) {
1621 if ((audiofd > -1) && (ctrlfd > -1))
1622 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1624 res = ast_waitstream(chan, ints);
1626 ast_stopstream(chan);
1633 char *separator_dziesiatek;
1637 char *dziesiatki[10];
1642 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1648 return odm->rzedy[rzad - 1][0];
1649 if ((i > 21 || i < 11) && i%10 > 1 && i%10 < 5)
1650 return odm->rzedy[rzad - 1][1];
1652 return odm->rzedy[rzad - 1][2];
1655 static char* pl_append(char* buffer, char* str)
1657 strcpy(buffer, str);
1658 buffer += strlen(str);
1662 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1664 char file_name[255] = "digits/";
1665 strcat(file_name, fn);
1666 ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
1667 if (!ast_streamfile(chan, file_name, language)) {
1668 if ((audiofd > -1) && (ctrlfd > -1))
1669 ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1671 ast_waitstream(chan, ints);
1673 ast_stopstream(chan);
1676 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1678 /* Initialise variables to allow compilation on Debian-stable, etc */
1688 if (i == 0 && rzad > 0) {
1692 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1695 m1000E6 = i % 1000000000;
1696 i1000E6 = i / 1000000000;
1698 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1700 m1000E3 = m1000E6 % 1000000;
1701 i1000E3 = m1000E6 / 1000000;
1703 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1705 m1000 = m1000E3 % 1000;
1706 i1000 = m1000E3 / 1000;
1708 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1714 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1716 if ( m100 > 0 && m100 <=9 ) {
1718 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1720 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1721 } else if (m100 % 10 == 0) {
1722 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1723 } else if (m100 <= 19 ) {
1724 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1725 } else if (m100 != 0) {
1726 if (odm->separator_dziesiatek[0]==' ') {
1727 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1728 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1732 b = pl_append(b, odm->dziesiatki[m100 / 10]);
1733 b = pl_append(b, odm->separator_dziesiatek);
1734 b = pl_append(b, odm->cyfry2[m100 % 10]);
1735 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1740 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1744 /* ast_say_number_full_pl: Polish syntax */
1745 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)
1755 1000000000.2 miliardy
1756 1000000000.5 miliardow
1820 70m siedemdziesieciu
1832 90m dziewiedziesieciu
1834 and combinations of eg.: 20_1, 30m_3m, etc...
1838 char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1840 char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1842 char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1844 char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1846 char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1848 char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1850 char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1852 char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1854 char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1856 char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1858 char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1860 char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1862 char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}};
1864 /* Initialise variables to allow compilation on Debian-stable, etc */
1867 static odmiana *odmiana_nieosobowa = NULL;
1868 static odmiana *odmiana_meska = NULL;
1869 static odmiana *odmiana_zenska = NULL;
1871 if (odmiana_nieosobowa == NULL) {
1872 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
1874 odmiana_nieosobowa->separator_dziesiatek = "_";
1876 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1877 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1878 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1879 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1880 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1881 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1884 if (odmiana_zenska == NULL) {
1885 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
1887 odmiana_zenska->separator_dziesiatek = " ";
1889 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
1890 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
1891 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
1892 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
1893 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
1894 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
1897 if (odmiana_meska == NULL) {
1898 odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
1900 odmiana_meska->separator_dziesiatek = " ";
1902 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
1903 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
1904 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
1905 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
1906 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
1907 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
1911 if (strncasecmp(options, "f", 1) == 0)
1913 else if (strncasecmp(options, "m", 1) == 0)
1916 o = odmiana_nieosobowa;
1918 o = odmiana_nieosobowa;
1920 powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
1924 /* ast_say_number_full_pt: Portuguese syntax */
1925 /* Extra sounds needed: */
1926 /* For feminin all sound files end with F */
1927 /* 100E for 100+ something */
1928 /* 1000000S for plural */
1929 /* pt-e for 'and' */
1930 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)
1934 int mf = 1; /* +1 = male; -1 = female */
1938 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1940 if (options && !strncasecmp(options, "f",1))
1943 while(!res && num ) {
1945 snprintf(fn, sizeof(fn), "digits/minus");
1946 if ( num > INT_MIN ) {
1951 } else if (num < 20) {
1952 if ((num == 1 || num == 2) && (mf < 0))
1953 snprintf(fn, sizeof(fn), "digits/%dF", num);
1955 snprintf(fn, sizeof(fn), "digits/%d", num);
1957 } else if (num < 100) {
1958 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
1962 } else if (num < 1000) {
1964 snprintf(fn, sizeof(fn), "digits/100");
1966 snprintf(fn, sizeof(fn), "digits/100E");
1968 if (mf < 0 && num > 199)
1969 snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
1971 snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
1976 } else if (num < 1000000) {
1978 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
1982 snprintf(fn, sizeof(fn), "digits/1000");
1983 if ((num % 1000) && ((num % 1000) < 100 || !(num % 100)))
1986 } else if (num < 1000000000) {
1987 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
1991 snprintf(fn, sizeof(fn), "digits/1000000");
1993 snprintf(fn, sizeof(fn), "digits/1000000S");
1995 if ((num % 1000000) &&
1997 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
1998 /* no hundreds and below */
1999 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
2001 num = num % 1000000;
2004 if (!ast_streamfile(chan, fn, language)) {
2005 if ((audiofd > -1) && (ctrlfd > -1))
2006 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2008 res = ast_waitstream(chan, ints);
2010 ast_stopstream(chan);
2012 if (!res && playh) {
2013 res = wait_file(chan, ints, "digits/pt-e", language);
2014 ast_stopstream(chan);
2021 /*! \brief ast_say_number_full_se: Swedish syntax */
2022 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)
2027 int cn = 1; /* +1 = commune; -1 = neuter */
2029 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2030 if (options && !strncasecmp(options, "n",1)) cn = -1;
2032 while(!res && (num || playh)) {
2034 snprintf(fn, sizeof(fn), "digits/minus");
2035 if ( num > INT_MIN ) {
2041 snprintf(fn, sizeof(fn), "digits/hundred");
2043 } else if (num < 20) {
2044 snprintf(fn, sizeof(fn), "digits/%d", num);
2046 } else if (num < 100) {
2047 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2048 num -= ((num / 10) * 10);
2049 } else if (num == 1 && cn == -1) { /* En eller ett? */
2050 snprintf(fn, sizeof(fn), "digits/1N");
2054 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2056 num -= ((num / 100) * 100);
2058 if (num < 1000000) { /* 1,000,000 */
2059 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2064 snprintf(fn, sizeof(fn), "digits/thousand");
2066 if (num < 1000000000) { /* 1,000,000,000 */
2067 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2071 num = num % 1000000;
2072 snprintf(fn, sizeof(fn), "digits/million");
2074 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2081 if(!ast_streamfile(chan, fn, language)) {
2082 if ((audiofd > -1) && (ctrlfd > -1))
2083 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2085 res = ast_waitstream(chan, ints);
2086 ast_stopstream(chan);
2093 /*! \brief ast_say_number_full_tw: Taiwanese syntax */
2094 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2100 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2102 while(!res && (num || playh)) {
2104 snprintf(fn, sizeof(fn), "digits/minus");
2105 if ( num > INT_MIN ) {
2111 snprintf(fn, sizeof(fn), "digits/hundred");
2113 } else if (num < 10) {
2114 snprintf(fn, sizeof(fn), "digits/%d", num);
2116 } else if (num < 100) {
2117 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2118 num -= ((num / 10) * 10);
2121 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2123 num -= ((num / 100) * 100);
2125 if (num < 1000000) { /* 1,000,000 */
2126 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
2130 snprintf(fn, sizeof(fn), "digits/thousand");
2132 if (num < 1000000000) { /* 1,000,000,000 */
2133 res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2136 num = num % 1000000;
2137 snprintf(fn, sizeof(fn), "digits/million");
2139 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2146 if(!ast_streamfile(chan, fn, language)) {
2147 if ((audiofd > -1) && (ctrlfd > -1))
2148 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2150 res = ast_waitstream(chan, ints);
2152 ast_stopstream(chan);
2159 /*! \brief determine last digits for thousands/millions (ru) */
2160 static int get_lastdigits_ru(int num) {
2163 } else if (num < 100) {
2164 return get_lastdigits_ru(num % 10);
2165 } else if (num < 1000) {
2166 return get_lastdigits_ru(num % 100);
2168 return 0; /* number too big */
2172 /*! \brief ast_say_number_full_ru: Russian syntax */
2173 /*! \brief additional files:
2174 n00.gsm (one hundred, two hundred, ...)
2177 thousands-i.gsm (tisyachi)
2178 million-a.gsm (milliona)
2184 where 'n' from 1 to 9
2186 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)
2192 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2194 while(!res && (num)) {
2196 snprintf(fn, sizeof(fn), "digits/minus");
2197 if ( num > INT_MIN ) {
2202 } else if (num < 20) {
2203 if(options && strlen(options) == 1 && num < 3) {
2204 snprintf(fn, sizeof(fn), "digits/%d%s", num, options);
2206 snprintf(fn, sizeof(fn), "digits/%d", num);
2209 } else if (num < 100) {
2210 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 10));
2212 } else if (num < 1000){
2213 snprintf(fn, sizeof(fn), "digits/%d", num - (num % 100));
2215 } else if (num < 1000000) { /* 1,000,000 */
2216 lastdigits = get_lastdigits_ru(num / 1000);
2218 if (lastdigits < 3) {
2219 res = ast_say_number_full_ru(chan, num / 1000, ints, language, "f", audiofd, ctrlfd);
2221 res = ast_say_number_full_ru(chan, num / 1000, ints, language, NULL, audiofd, ctrlfd);
2225 if (lastdigits == 1) {
2226 snprintf(fn, sizeof(fn), "digits/thousand");
2227 } else if (lastdigits > 1 && lastdigits < 5) {
2228 snprintf(fn, sizeof(fn), "digits/thousands-i");
2230 snprintf(fn, sizeof(fn), "digits/thousands");
2233 } else if (num < 1000000000) { /* 1,000,000,000 */
2234 lastdigits = get_lastdigits_ru(num / 1000000);
2236 res = ast_say_number_full_ru(chan, num / 1000000, ints, language, NULL, audiofd, ctrlfd);
2239 if (lastdigits == 1) {
2240 snprintf(fn, sizeof(fn), "digits/million");
2241 } else if (lastdigits > 1 && lastdigits < 5) {
2242 snprintf(fn, sizeof(fn), "digits/million-a");
2244 snprintf(fn, sizeof(fn), "digits/millions");
2248 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2252 if (!ast_streamfile(chan, fn, language)) {
2253 if ((audiofd > -1) && (ctrlfd > -1))
2254 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2256 res = ast_waitstream(chan, ints);
2258 ast_stopstream(chan);
2265 /*! \brief ast_say_enumeration_full: call language-specific functions */
2266 /* Called from AGI */
2267 int ast_say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2269 if (!strcasecmp(language,"en") ) { /* English syntax */
2270 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2271 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
2272 return(ast_say_enumeration_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
2273 } else if (!strcasecmp(language, "de") ) { /* German syntax */
2274 return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2277 /* Default to english */
2278 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2281 /*! \brief ast_say_enumeration: call language-specific functions without file descriptors */
2282 int ast_say_enumeration(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
2284 return(ast_say_enumeration_full(chan, num, ints, language, options, -1, -1));
2287 /*! \brief ast_say_enumeration_full_en: English syntax */
2288 /* This is the default syntax, if no other syntax defined in this file is used */
2289 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2294 while(!res && num) {
2296 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2297 if ( num > INT_MIN ) {
2302 } else if (num < 20) {
2303 snprintf(fn, sizeof(fn), "digits/h-%d", num);
2305 } else if (num < 100) {
2306 int tens = num / 10;
2309 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2311 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2313 } else if (num < 1000) {
2314 int hundreds = num / 100;
2316 if (hundreds > 1 || t == 1) {
2317 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2322 snprintf(fn, sizeof(fn), "digits/hundred");
2324 snprintf(fn, sizeof(fn), "digits/h-hundred");
2326 } else if (num < 1000000) {
2327 int thousands = num / 1000;
2329 if (thousands > 1 || t == 1) {
2330 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2335 snprintf(fn, sizeof(fn), "digits/thousand");
2337 snprintf(fn, sizeof(fn), "digits/h-thousand");
2340 } else if (num < 1000000000) {
2341 int millions = num / 1000000;
2342 num = num % 1000000;
2344 res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2348 snprintf(fn, sizeof(fn), "digits/million");
2350 snprintf(fn, sizeof(fn), "digits/h-million");
2352 } else if (num < INT_MAX) {
2353 int billions = num / 1000000000;
2354 num = num % 1000000000;
2356 res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2360 snprintf(fn, sizeof(fn), "digits/billion");
2362 snprintf(fn, sizeof(fn), "digits/h-billion");
2364 } else if (num == INT_MAX) {
2365 snprintf(fn, sizeof(fn), "digits/h-last");
2368 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2373 if (!ast_streamfile(chan, fn, language)) {
2374 if ((audiofd > -1) && (ctrlfd > -1)) {
2375 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2377 res = ast_waitstream(chan, ints);
2380 ast_stopstream(chan);
2386 /*! \brief ast_say_enumeration_full_da: Danish syntax */
2387 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)
2389 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2391 char fn[256] = "", fna[256] = "";
2394 if (options && !strncasecmp(options, "f",1)) {
2396 } else if (options && !strncasecmp(options, "n",1)) {
2403 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2405 while(!res && num) {
2407 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2408 if ( num > INT_MIN ) {
2413 } else if (num < 100 && t) {
2414 snprintf(fn, sizeof(fn), "digits/and");
2416 } else if (num < 20) {
2417 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2419 } else if (num < 100) {
2420 int ones = num % 10;
2422 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2425 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2428 } else if (num == 100 && t == 0) {
2429 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2431 } else if (num < 1000) {
2432 int hundreds = num / 100;
2434 if (hundreds == 1) {
2435 snprintf(fn, sizeof(fn), "digits/1N");
2437 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2440 snprintf(fna, sizeof(fna), "digits/hundred");
2442 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2445 } else if (num < 1000000) {
2446 int thousands = num / 1000;
2448 if (thousands == 1) {
2450 snprintf(fn, sizeof(fn), "digits/1N");
2451 snprintf(fna, sizeof(fna), "digits/thousand");
2454 snprintf(fn, sizeof(fn), "digits/1N");
2455 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2457 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2461 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2466 snprintf(fn, sizeof(fn), "digits/thousand");
2468 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2472 } else if (num < 1000000000) {
2473 int millions = num / 1000000;
2474 num = num % 1000000;
2475 if (millions == 1) {
2477 snprintf(fn, sizeof(fn), "digits/1F");
2478 snprintf(fna, sizeof(fna), "digits/million");
2480 snprintf(fn, sizeof(fn), "digits/1N");
2481 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2484 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2489 snprintf(fn, sizeof(fn), "digits/millions");
2491 snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2495 } else if (num < INT_MAX) {
2496 int billions = num / 1000000000;
2497 num = num % 1000000000;
2498 if (billions == 1) {
2500 snprintf(fn, sizeof(fn), "digits/1F");
2501 snprintf(fna, sizeof(fna), "digits/milliard");
2503 snprintf(fn, sizeof(fn), "digits/1N");
2504 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2507 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2511 snprintf(fn, sizeof(fna), "digits/milliards");
2513 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2517 } else if (num == INT_MAX) {
2518 snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2521 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2526 if (!ast_streamfile(chan, fn, language)) {
2527 if ((audiofd > -1) && (ctrlfd > -1))
2528 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2530 res = ast_waitstream(chan, ints);
2532 ast_stopstream(chan);
2534 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2535 if ((audiofd > -1) && (ctrlfd > -1)) {
2536 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2538 res = ast_waitstream(chan, ints);
2541 ast_stopstream(chan);
2549 /*! \brief ast_say_enumeration_full_de: German syntax */
2550 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)
2552 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2554 char fn[256] = "", fna[256] = "";
2557 if (options && !strncasecmp(options, "f",1)) {
2559 } else if (options && !strncasecmp(options, "n",1)) {
2566 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2568 while(!res && num) {
2570 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2571 if ( num > INT_MIN ) {
2576 } else if (num < 100 && t) {
2577 snprintf(fn, sizeof(fn), "digits/and");
2579 } else if (num < 20) {
2580 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2582 } else if (num < 100) {
2583 int ones = num % 10;
2585 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2588 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2591 } else if (num == 100 && t == 0) {
2592 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2594 } else if (num < 1000) {
2595 int hundreds = num / 100;
2597 if (hundreds == 1) {
2598 snprintf(fn, sizeof(fn), "digits/1N");
2600 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2603 snprintf(fna, sizeof(fna), "digits/hundred");
2605 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2608 } else if (num < 1000000) {
2609 int thousands = num / 1000;
2611 if (thousands == 1) {
2613 snprintf(fn, sizeof(fn), "digits/1N");
2614 snprintf(fna, sizeof(fna), "digits/thousand");
2617 snprintf(fn, sizeof(fn), "digits/1N");
2618 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2620 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2624 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2629 snprintf(fn, sizeof(fn), "digits/thousand");
2631 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2635 } else if (num < 1000000000) {
2636 int millions = num / 1000000;
2637 num = num % 1000000;
2638 if (millions == 1) {
2640 snprintf(fn, sizeof(fn), "digits/1F");
2641 snprintf(fna, sizeof(fna), "digits/million");
2643 snprintf(fn, sizeof(fn), "digits/1N");
2644 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2647 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2652 snprintf(fn, sizeof(fn), "digits/millions");
2654 snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2658 } else if (num < INT_MAX) {
2659 int billions = num / 1000000000;
2660 num = num % 1000000000;
2661 if (billions == 1) {
2663 snprintf(fn, sizeof(fn), "digits/1F");
2664 snprintf(fna, sizeof(fna), "digits/milliard");
2666 snprintf(fn, sizeof(fn), "digits/1N");
2667 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2670 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2674 snprintf(fn, sizeof(fna), "digits/milliards");
2676 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2680 } else if (num == INT_MAX) {
2681 snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2684 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2689 if (!ast_streamfile(chan, fn, language)) {
2690 if ((audiofd > -1) && (ctrlfd > -1))
2691 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2693 res = ast_waitstream(chan, ints);
2695 ast_stopstream(chan);
2697 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2698 if ((audiofd > -1) && (ctrlfd > -1)) {
2699 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2701 res = ast_waitstream(chan, ints);
2704 ast_stopstream(chan);
2712 int ast_say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2714 if (!strcasecmp(lang, "en") ) { /* English syntax */
2715 return(ast_say_date_en(chan, t, ints, lang));
2716 } else if (!strcasecmp(lang, "da") ) { /* Danish syntax */
2717 return(ast_say_date_da(chan, t, ints, lang));
2718 } else if (!strcasecmp(lang, "de") ) { /* German syntax */
2719 return(ast_say_date_de(chan, t, ints, lang));
2720 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */
2721 return(ast_say_date_fr(chan, t, ints, lang));
2722 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */
2723 return(ast_say_date_nl(chan, t, ints, lang));
2724 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */
2725 return(ast_say_date_pt(chan, t, ints, lang));
2726 } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */
2727 return(ast_say_date_gr(chan, t, ints, lang));
2730 /* Default to English */
2731 return(ast_say_date_en(chan, t, ints, lang));
2734 /* English syntax */
2735 int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2740 ast_localtime(&t,&tm,NULL);
2742 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2743 res = ast_streamfile(chan, fn, lang);
2745 res = ast_waitstream(chan, ints);
2748 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2749 res = ast_streamfile(chan, fn, lang);
2751 res = ast_waitstream(chan, ints);
2754 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2756 res = ast_waitstream(chan, ints);
2758 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2763 int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2768 ast_localtime(&t,&tm,NULL);
2770 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2771 res = ast_streamfile(chan, fn, lang);
2773 res = ast_waitstream(chan, ints);
2776 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2778 res = ast_waitstream(chan, ints);
2780 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2781 res = ast_streamfile(chan, fn, lang);
2783 res = ast_waitstream(chan, ints);
2787 int year = tm.tm_year + 1900;
2788 if (year > 1999) { /* year 2000 and later */
2789 res = ast_say_number(chan, year, ints, lang, (char *) NULL);
2792 /* I'm not going to handle 1100 and prior */
2793 /* We'll just be silent on the year, instead of bombing out. */
2795 /* year 1100 to 1999. will anybody need this?!? */
2796 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) );
2797 res = wait_file(chan, ints, fn, lang);
2799 res = wait_file(chan,ints, "digits/hundred", lang);
2800 if (!res && year % 100 != 0) {
2801 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
2811 int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2816 ast_localtime(&t,&tm,NULL);
2818 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2819 res = ast_streamfile(chan, fn, lang);