2 * Asterisk -- A telephony toolkit for Linux.
4 * Say numbers and dates (maybe words one day too)
6 * Copyright (C) 1999, Mark Spencer
8 * Mark Spencer <markster@linux-support.net>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
13 * 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr)
14 * George Konstantoulakis <gkon@inaccessnetworks.com>
17 #include <sys/types.h>
20 #include <netinet/in.h>
24 #include <asterisk/file.h>
25 #include <asterisk/channel.h>
26 #include <asterisk/logger.h>
27 #include <asterisk/say.h>
28 #include <asterisk/lock.h>
29 #include <asterisk/localtime.h>
30 #include <asterisk/utils.h>
35 #include <iso/limits_iso.h>
39 /* Forward declaration */
40 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
42 int ast_say_digit_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
44 /* XXX Merge with full version? XXX */
48 while(fn2[num] && !res) {
52 snprintf(fn, sizeof(fn), "digits/star");
55 snprintf(fn, sizeof(fn), "digits/pound");
58 if((fn2[num] >= '0') && (fn2[num] <= '9')){ /* Must be in {0-9} */
59 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
62 if(!ast_strlen_zero(fn)){ /* if length == 0, then skip this digit as it is invalid */
63 res = ast_streamfile(chan, fn, lang);
65 res = ast_waitstream(chan, ints);
73 int ast_say_character_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
75 /* XXX Merge with full version? XXX */
80 while(fn2[num] && !res) {
84 snprintf(fn, sizeof(fn), "digits/star");
87 snprintf(fn, sizeof(fn), "digits/pound");
99 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
102 strncpy(fn, "letters/exclaimation-point", sizeof(fn));
105 strncpy(fn, "letters/at", sizeof(fn));
108 strncpy(fn, "letters/dollar", sizeof(fn));
111 strncpy(fn, "letters/dash", sizeof(fn));
114 strncpy(fn, "letters/dot", sizeof(fn));
117 strncpy(fn, "letters/equals", sizeof(fn));
120 strncpy(fn, "letters/plus", sizeof(fn));
123 strncpy(fn, "letters/slash", sizeof(fn));
126 strncpy(fn, "letters/space", sizeof(fn));
130 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
131 snprintf(fn, sizeof(fn), "letters/%c", ltr);
133 if(!ast_strlen_zero(fn)) { /* if length == 0, then skip this digit as it is invalid */
134 res = ast_streamfile(chan, fn, lang);
136 res = ast_waitstream(chan, ints);
137 } ast_stopstream(chan);
143 int ast_say_phonetic_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
145 /* XXX Merge with full version? XXX */
153 /* while(fn2[num] && !res) { */
158 snprintf(fn, sizeof(fn), "digits/star");
161 snprintf(fn, sizeof(fn), "digits/pound");
172 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
175 strncpy(fn, "exclaimation-point", sizeof(fn));
178 strncpy(fn, "at", sizeof(fn));
181 strncpy(fn, "dollar", sizeof(fn));
184 strncpy(fn, "dash", sizeof(fn));
187 strncpy(fn, "dot", sizeof(fn));
190 strncpy(fn, "equals", sizeof(fn));
193 strncpy(fn, "plus", sizeof(fn));
196 strncpy(fn, "slash", sizeof(fn));
199 strncpy(fn, "space", sizeof(fn));
203 /* check if we have 2 chars after the % */
204 if (strlen(fn2) > num+2)
209 if (sscanf(hex,"%x", &temp))
210 { /* Hex to char convertion successfull */
213 { /* If it is a percent, play it now */
214 strncpy(fn, "percent", sizeof(fn));
218 /* check for invalid characters */
219 if ((temp<32) || (temp>126))
228 default: /* '9' falls through to here, too */
229 ltr = tolower(fn2[num]);
230 snprintf(fn, sizeof(fn), "phonetic/%c_p", ltr);
234 res = ast_streamfile(chan, fn, lang);
236 res = ast_waitstream(chan, ints);
237 ast_stopstream(chan);
244 int ast_say_digit_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
249 while(fn2[num] && !res) {
250 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
251 res = ast_streamfile(chan, fn, lang);
253 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
254 ast_stopstream(chan);
260 int ast_say_character_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
266 while(fn2[num] && !res) {
269 snprintf(fn, sizeof(fn), "digits/star");
272 snprintf(fn, sizeof(fn), "digits/pound");
284 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
287 strncpy(fn, "exclaimation-point", sizeof(fn));
290 strncpy(fn, "at", sizeof(fn));
293 strncpy(fn, "dollar", sizeof(fn));
296 strncpy(fn, "dash", sizeof(fn));
299 strncpy(fn, "dot", sizeof(fn));
302 strncpy(fn, "equals", sizeof(fn));
305 strncpy(fn, "plus", sizeof(fn));
308 strncpy(fn, "slash", sizeof(fn));
311 strncpy(fn, "space", sizeof(fn));
315 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
316 snprintf(fn, sizeof(fn), "letters/%c", ltr);
318 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
319 res = ast_streamfile(chan, fn, lang);
321 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
322 ast_stopstream(chan);
328 int ast_say_phonetic_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
334 while(fn2[num] && !res) {
337 snprintf(fn, sizeof(fn), "digits/star");
340 snprintf(fn, sizeof(fn), "digits/pound");
351 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
354 strncpy(fn, "exclaimation-point", sizeof(fn));
357 strncpy(fn, "at", sizeof(fn));
360 strncpy(fn, "dollar", sizeof(fn));
363 strncpy(fn, "dash", sizeof(fn));
366 strncpy(fn, "dot", sizeof(fn));
369 strncpy(fn, "equals", sizeof(fn));
372 strncpy(fn, "plus", sizeof(fn));
375 strncpy(fn, "slash", sizeof(fn));
378 strncpy(fn, "space", sizeof(fn));
380 default: /* '9' falls here... */
382 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
383 snprintf(fn, sizeof(fn), "phonetic/%c", ltr);
385 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
386 res = ast_streamfile(chan, fn, lang);
388 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
389 ast_stopstream(chan);
395 int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
397 /* XXX Should I be merged with say_digits_full XXX */
399 snprintf(fn2, sizeof(fn2), "%d", num);
400 return ast_say_digit_str(chan, fn2, ints, lang);
403 int ast_say_digits_full(struct ast_channel *chan, int num, const char *ints, const char *lang, int audiofd, int ctrlfd)
406 snprintf(fn2, sizeof(fn2), "%d", num);
407 return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
410 /* Forward declarations */
411 /* Syntaxes supported, not really language codes.
415 en_GB - English (British)
416 es - Spanish, Mexican
427 For Some languages the numbers differ for gender and plural
428 Use the option argument 'f' for female, 'm' for male and 'n' for neuter in languages like Portuguese, French, Spanish and German.
429 use the option argument 'c' is for commune and 'n' for neuter gender in nordic languages like Danish, Swedish and Norwegian.
430 use the option argument 'p' for plural enumerations like in German
432 Date/Time functions currently have less languages supported than saynumber().
434 Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
436 See contrib/i18n.testsuite.conf for some examples of the different syntaxes
438 Portuguese sound files needed for Time/Date functions:
448 Spanish sound files needed for Time/Date functions:
452 Italian sound files needed for Time/Date functions:
458 /* Forward declarations of language specific variants of ast_say_number_full */
459 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
460 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);
461 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);
462 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);
463 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
464 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);
465 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);
466 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
467 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
468 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);
469 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);
470 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);
471 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);
472 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
473 static int ast_say_number_full_gr(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
475 /* Forward declarations of language specific variants of ast_say_enumeration_full */
476 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
477 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);
478 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);
480 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
481 static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
482 static int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
483 static int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
484 static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
485 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
486 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
487 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
489 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);
490 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);
491 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);
492 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);
493 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);
494 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);
495 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);
496 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);
497 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);
498 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);
500 static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
501 static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
502 static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
503 static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
504 static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
505 static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
506 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
508 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
509 static int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
510 static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
511 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
512 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
513 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
514 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
516 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
517 static int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
518 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
520 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang)
523 if ((res = ast_streamfile(chan, file, lang)))
524 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
526 res = ast_waitstream(chan, ints);
530 /*--- ast_say_number_full: call language-specific functions */
531 /* Called from AGI */
532 int ast_say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
534 if (!strcasecmp(language,"en") ) { /* English syntax */
535 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
536 } else if (!strcasecmp(language, "cz") ) { /* Czech syntax */
537 return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd));
538 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
539 return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
540 } else if (!strcasecmp(language, "de") ) { /* German syntax */
541 return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
542 } else if (!strcasecmp(language, "en_GB") ) { /* British syntax */
543 return(ast_say_number_full_en_GB(chan, num, ints, language, audiofd, ctrlfd));
544 } else if (!strcasecmp(language, "no") ) { /* Norwegian syntax */
545 return(ast_say_number_full_no(chan, num, ints, language, options, audiofd, ctrlfd));
546 } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) { /* Spanish syntax */
547 return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd));
548 } else if (!strcasecmp(language, "fr") ) { /* French syntax */
549 return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd));
550 } else if (!strcasecmp(language, "it") ) { /* Italian syntax */
551 return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd));
552 } else if (!strcasecmp(language, "nl") ) { /* Dutch syntax */
553 return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd));
554 } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */
555 return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd));
556 } else if (!strcasecmp(language, "pt") ) { /* Portuguese syntax */
557 return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd));
558 } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */
559 return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd));
560 } else if (!strcasecmp(language, "tw")) { /* Taiwanese syntax */
561 return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd));
562 } else if (!strcasecmp(language, "gr") ) { /* Greek syntax */
563 return(ast_say_number_full_gr(chan, num, ints, language, audiofd, ctrlfd));
566 /* Default to english */
567 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
570 /*--- ast_say_number: call language-specific functions without file descriptors */
571 int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
573 return(ast_say_number_full(chan, num, ints, language, options, -1, -1));
576 /*--- ast_say_number_full_en: English syntax */
577 /* This is the default syntax, if no other syntax defined in this file is used */
578 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
584 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
586 while(!res && (num || playh)) {
588 snprintf(fn, sizeof(fn), "digits/minus");
589 if ( num > INT_MIN ) {
595 snprintf(fn, sizeof(fn), "digits/hundred");
597 } else if (num < 20) {
598 snprintf(fn, sizeof(fn), "digits/%d", num);
600 } else if (num < 100) {
601 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
602 num -= ((num / 10) * 10);
605 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
607 num -= ((num / 100) * 100);
609 if (num < 1000000) { /* 1,000,000 */
610 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
614 snprintf(fn, sizeof(fn), "digits/thousand");
616 if (num < 1000000000) { /* 1,000,000,000 */
617 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
621 snprintf(fn, sizeof(fn), "digits/million");
623 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
630 if(!ast_streamfile(chan, fn, language)) {
631 if ((audiofd > -1) && (ctrlfd > -1))
632 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
634 res = ast_waitstream(chan, ints);
636 ast_stopstream(chan);
642 static int exp10_int(int power)
645 for (x=0;x<power;x++)
650 /*--- ast_say_number_full_cz: Czech syntax */
652 * 1m,2m - gender male
653 * 1w,2w - gender female
657 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set
659 * for each number 10^(3n + 3) exist 3 files represented as:
660 * 1 tousand = jeden tisic = 1_E3
661 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
662 * 5,6,... tousands = pet,sest,... tisic = 5_E3
668 * tousand, milion are gender male, so 1 and 2 is 1m 2m
669 * miliard is gender female, so 1 and 2 is 1w 2w
671 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)
681 /* options - w = woman, m = man, n = neutral. Defaultl is woman */
686 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
688 while(!res && (num || playh)) {
690 snprintf(fn, sizeof(fn), "digits/minus");
691 if ( num > INT_MIN ) {
696 } else if (num < 3 ) {
697 snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]);
700 } else if (num < 20) {
701 snprintf(fn, sizeof(fn), "digits/%d",num);
704 } else if (num < 100) {
705 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
706 num -= ((num / 10) * 10);
707 } else if (num < 1000) {
708 hundered = num / 100;
709 if ( hundered == 1 ) {
710 snprintf(fn, sizeof(fn), "digits/1sto");
711 } else if ( hundered == 2 ) {
712 snprintf(fn, sizeof(fn), "digits/2ste");
714 res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd);
717 if (hundered == 3 || hundered == 4) {
718 snprintf(fn, sizeof(fn), "digits/sta");
719 } else if ( hundered > 4 ) {
720 snprintf(fn, sizeof(fn), "digits/set");
723 num -= (hundered * 100);
724 } else { /* num > 1000 */
725 length = (int)log10(num)+1;
726 while ( (length % 3 ) != 1 ) {
729 left = num / (exp10_int(length-1));
732 case 9: options = "w"; /* 1,000,000,000 gender female */
734 default : options = "m"; /* others are male */
737 if ( left > 1 ) { /* we dont say "one thousand" but only thousand */
738 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd);
742 if ( left >= 5 ) { /* >= 5 have the same declesion */
743 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1);
744 } else if ( left >= 2 && left <= 4 ) {
745 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1);
746 } else { /* left == 1 */
747 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1);
749 num -= left * (exp10_int(length-1));
752 if(!ast_streamfile(chan, fn, language)) {
753 if ((audiofd > -1) && (ctrlfd > -1)) {
754 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
756 res = ast_waitstream(chan, ints);
759 ast_stopstream(chan);
765 /*--- ast_say_number_full_da: Danish syntax */
767 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and"
769 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)
774 int cn = 1; /* +1 = commune; -1 = neuter */
777 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
779 if (options && !strncasecmp(options, "n",1)) cn = -1;
781 while(!res && (num || playh || playa )) {
782 /* The grammar for Danish numbers is the same as for English except
784 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1")
785 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
786 * "one-and twenty" and 68 is "eight-and sixty".
787 * - "million" is different in singular and plural form
788 * - numbers > 1000 with zero as the third digit from last have an
789 * "and" before the last two digits, i.e. 2034 is "two thousand and
790 * four-and thirty" and 1000012 is "one million and twelve".
793 snprintf(fn, sizeof(fn), "digits/minus");
794 if ( num > INT_MIN ) {
800 snprintf(fn, sizeof(fn), "digits/hundred");
803 snprintf(fn, sizeof(fn), "digits/and");
805 } else if (num == 1 && cn == -1) {
806 snprintf(fn, sizeof(fn), "digits/1N");
808 } else if (num < 20) {
809 snprintf(fn, sizeof(fn), "digits/%d", num);
811 } else if (num < 100) {
814 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
817 snprintf(fn, sizeof(fn), "digits/%d", num);
822 int hundreds = num / 100;
824 snprintf(fn, sizeof(fn), "digits/1N");
826 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
829 num -= 100 * hundreds;
835 res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
839 snprintf(fn, sizeof(fn), "digits/thousand");
841 if (num < 1000000000) {
842 int millions = num / 1000000;
843 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
847 snprintf(fn, sizeof(fn), "digits/million");
849 snprintf(fn, sizeof(fn), "digits/millions");
852 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
856 if (num && num < 100)
861 if(!ast_streamfile(chan, fn, language)) {
862 if ((audiofd > -1) && (ctrlfd > -1))
863 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
865 res = ast_waitstream(chan, ints);
867 ast_stopstream(chan);
873 /*--- ast_say_number_full_de: German syntax */
875 In addition to English, the following sounds are required:
877 "1-and" through "9-and"
880 NB "1" is recorded as 'eins'
882 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)
885 int mf = 1; /* +1 = male and neuter; -1 = female */
889 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
891 if (options && (!strncasecmp(options, "f",1)))
895 /* The grammar for German numbers is the same as for English except
897 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
898 * "one-and twenty" and 68 is "eight-and sixty".
899 * - "one" varies according to gender
900 * - 100 is 'hundert', however all other instances are 'ein hundert'
901 * - 1000 is 'tausend', however all other instances are 'ein tausend'
902 * - 1000000 is always 'eine million'
903 * - "million" is different in singular and plural form
906 snprintf(fn, sizeof(fn), "digits/minus");
907 if ( num > INT_MIN ) {
912 } else if (num < 100 && t) {
913 snprintf(fn, sizeof(fn), "digits/and");
915 } else if (num == 1 && mf == -1) {
916 snprintf(fn, sizeof(fn), "digits/%dF", num);
918 } else if (num < 20) {
919 snprintf(fn, sizeof(fn), "digits/%d", num);
921 } else if (num < 100) {
924 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
927 snprintf(fn, sizeof(fn), "digits/%d", num);
930 } else if (num == 100 && t == 0) {
931 snprintf(fn, sizeof(fn), "digits/hundred");
933 } else if (num < 1000) {
934 int hundreds = num / 100;
937 snprintf(fn, sizeof(fn), "digits/1N");
939 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
941 snprintf(fna, sizeof(fna), "digits/hundred");
943 } else if (num == 1000 && t == 0) {
944 snprintf(fn, sizeof(fn), "digits/thousand");
946 } else if (num < 1000000) {
947 int thousands = num / 1000;
950 if (thousands == 1) {
951 snprintf(fn, sizeof(fn), "digits/1N");
952 snprintf(fna, sizeof(fna), "digits/thousand");
954 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
957 snprintf(fn, sizeof(fn), "digits/thousand");
959 } else if (num < 1000000000) {
960 int millions = num / 1000000;
964 snprintf(fn, sizeof(fn), "digits/1F");
965 snprintf(fna, sizeof(fna), "digits/million");
967 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
970 snprintf(fn, sizeof(fn), "digits/millions");
972 } else if (num <= INT_MAX) {
973 int billions = num / 1000000000;
974 num = num % 1000000000;
977 snprintf(fn, sizeof(fn), "digits/1F");
978 snprintf(fna, sizeof(fna), "digits/milliard");
980 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
984 snprintf(fn, sizeof(fn), "digits/milliards");
987 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
991 if(!ast_streamfile(chan, fn, language)) {
992 if ((audiofd > -1) && (ctrlfd > -1))
993 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
995 res = ast_waitstream(chan, ints);
997 ast_stopstream(chan);
999 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
1000 if ((audiofd > -1) && (ctrlfd > -1))
1001 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1003 res = ast_waitstream(chan, ints);
1005 ast_stopstream(chan);
1013 /*--- ast_say_number_full_en_GB: British and Norwegian syntax */
1015 In addition to American English, the following sounds are required: "and"
1017 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1024 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1026 while(!res && (num || playh || playa )) {
1028 snprintf(fn, sizeof(fn), "digits/minus");
1029 if ( num > INT_MIN ) {
1035 snprintf(fn, sizeof(fn), "digits/hundred");
1038 snprintf(fn, sizeof(fn), "digits/and");
1040 } else if (num < 20) {
1041 snprintf(fn, sizeof(fn), "digits/%d", num);
1043 } else if (num < 100) {
1044 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1045 num -= ((num / 10) * 10);
1046 } else if (num < 1000) {
1047 int hundreds = num / 100;
1048 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1051 num -= 100 * hundreds;
1054 } else if (num < 1000000) {
1055 res = ast_say_number_full_en_GB(chan, num / 1000, ints, language, audiofd, ctrlfd);
1058 snprintf(fn, sizeof(fn), "digits/thousand");
1060 if (num && num < 100)
1062 } else if (num < 1000000000) {
1063 int millions = num / 1000000;
1064 res = ast_say_number_full_en_GB(chan, millions, ints, language, audiofd, ctrlfd);
1067 snprintf(fn, sizeof(fn), "digits/million");
1068 num = num % 1000000;
1069 if (num && num < 100)
1072 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1077 if(!ast_streamfile(chan, fn, language)) {
1078 if ((audiofd > -1) && (ctrlfd > -1))
1079 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1081 res = ast_waitstream(chan, ints);
1083 ast_stopstream(chan);
1089 /*--- ast_say_number_full_es: Spanish syntax */
1091 Requires a few new audios:
1092 1F.gsm: feminine 'una'
1093 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
1095 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)
1099 int mf = 0; /* +1 = male; -1 = female */
1102 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1105 if (!strncasecmp(options, "f",1))
1107 else if (!strncasecmp(options, "m", 1))
1111 while (!res && num) {
1113 snprintf(fn, sizeof(fn), "digits/minus");
1114 if ( num > INT_MIN ) {
1120 snprintf(fn, sizeof(fn), "digits/and");
1122 } else if (num == 1) {
1124 snprintf(fn, sizeof(fn), "digits/%dF", num);
1126 snprintf(fn, sizeof(fn), "digits/%dM", num);
1128 snprintf(fn, sizeof(fn), "digits/%d", num);
1130 } else if (num < 31) {
1131 snprintf(fn, sizeof(fn), "digits/%d", num);
1133 } else if (num < 100) {
1134 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1135 num -= ((num/10)*10);
1138 } else if (num == 100) {
1139 snprintf(fn, sizeof(fn), "digits/100");
1141 } else if (num < 200) {
1142 snprintf(fn, sizeof(fn), "digits/100-and");
1146 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
1147 num -= ((num/100)*100);
1148 } else if (num < 2000) {
1150 snprintf(fn, sizeof(fn), "digits/thousand");
1152 if (num < 1000000) {
1153 res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1157 snprintf(fn, sizeof(fn), "digits/thousand");
1159 if (num < 2147483640) {
1160 if ((num/1000000) == 1) {
1161 res = ast_say_number_full_es(chan, num / 1000000, ints, language, "M", audiofd, ctrlfd);
1164 snprintf(fn, sizeof(fn), "digits/million");
1166 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1169 snprintf(fn, sizeof(fn), "digits/millions");
1171 num = num % 1000000;
1173 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1181 if(!ast_streamfile(chan, fn, language)) {
1182 if ((audiofd > -1) && (ctrlfd > -1))
1183 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1185 res = ast_waitstream(chan, ints);
1187 ast_stopstream(chan);
1195 /*--- ast_say_number_full_fr: French syntax */
1196 /* Extra sounds needed:
1199 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)
1204 int mf = 1; /* +1 = male; -1 = female */
1207 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1209 if (options && !strncasecmp(options, "f",1))
1212 while(!res && (num || playh || playa)) {
1214 snprintf(fn, sizeof(fn), "digits/minus");
1215 if ( num > INT_MIN ) {
1221 snprintf(fn, sizeof(fn), "digits/hundred");
1224 snprintf(fn, sizeof(fn), "digits/et");
1226 } else if (num == 1) {
1228 snprintf(fn, sizeof(fn), "digits/%dF", num);
1230 snprintf(fn, sizeof(fn), "digits/%d", num);
1232 } else if (num < 21) {
1233 snprintf(fn, sizeof(fn), "digits/%d", num);
1235 } else if (num < 70) {
1236 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1237 if ((num % 10) == 1) playa++;
1239 } else if (num < 80) {
1240 snprintf(fn, sizeof(fn), "digits/60");
1241 if ((num % 10) == 1) playa++;
1243 } else if (num < 100) {
1244 snprintf(fn, sizeof(fn), "digits/80");
1246 } else if (num < 200) {
1247 snprintf(fn, sizeof(fn), "digits/hundred");
1249 } else if (num < 1000) {
1250 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1253 } else if (num < 2000) {
1254 snprintf(fn, sizeof(fn), "digits/thousand");
1256 } else if (num < 1000000) {
1257 res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1260 snprintf(fn, sizeof(fn), "digits/thousand");
1262 } else if (num < 1000000000) {
1263 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1266 snprintf(fn, sizeof(fn), "digits/million");
1267 num = num % 1000000;
1269 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1273 if(!ast_streamfile(chan, fn, language)) {
1274 if ((audiofd > -1) && (ctrlfd > -1))
1275 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1277 res = ast_waitstream(chan, ints);
1279 ast_stopstream(chan);
1285 /*--- ast_say_number_full_it: Italian */
1286 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1294 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1299 Like english, numbers up to 20 are a single 'word', and others
1300 compound, but with exceptions.
1301 For example 21 is not twenty-one, but there is a single word in 'it'.
1302 Idem for 28 (ie when a the 2nd part of a compund number
1303 starts with a vowel)
1305 There are exceptions also for hundred, thousand and million.
1306 In english 100 = one hundred, 200 is two hundred.
1307 In italian 100 = cento , like to say hundred (without one),
1308 200 and more are like english.
1310 Same applies for thousand:
1311 1000 is one thousand in en, 2000 is two thousand.
1312 In it we have 1000 = mille , 2000 = 2 mila
1314 For million(s) we use the plural, if more than one
1315 Also, one million is abbreviated in it, like on-million,
1316 or 'un milione', not 'uno milione'.
1317 So the right file is provided.
1320 while(!res && (num || playh)) {
1322 snprintf(fn, sizeof(fn), "digits/minus");
1323 if ( num > INT_MIN ) {
1329 snprintf(fn, sizeof(fn), "digits/hundred");
1331 } else if (num < 20) {
1332 snprintf(fn, sizeof(fn), "digits/%d", num);
1334 } else if (num == 21) {
1335 snprintf(fn, sizeof(fn), "digits/%d", num);
1337 } else if (num == 28) {
1338 snprintf(fn, sizeof(fn), "digits/%d", num);
1340 } else if (num == 31) {
1341 snprintf(fn, sizeof(fn), "digits/%d", num);
1343 } else if (num == 38) {
1344 snprintf(fn, sizeof(fn), "digits/%d", num);
1346 } else if (num == 41) {
1347 snprintf(fn, sizeof(fn), "digits/%d", num);
1349 } else if (num == 48) {
1350 snprintf(fn, sizeof(fn), "digits/%d", num);
1352 } else if (num == 51) {
1353 snprintf(fn, sizeof(fn), "digits/%d", num);
1355 } else if (num == 58) {
1356 snprintf(fn, sizeof(fn), "digits/%d", num);
1358 } else if (num == 61) {
1359 snprintf(fn, sizeof(fn), "digits/%d", num);
1361 } else if (num == 68) {
1362 snprintf(fn, sizeof(fn), "digits/%d", num);
1364 } else if (num == 71) {
1365 snprintf(fn, sizeof(fn), "digits/%d", num);
1367 } else if (num == 78) {
1368 snprintf(fn, sizeof(fn), "digits/%d", num);
1370 } else if (num == 81) {
1371 snprintf(fn, sizeof(fn), "digits/%d", num);
1373 } else if (num == 88) {
1374 snprintf(fn, sizeof(fn), "digits/%d", num);
1376 } else if (num == 91) {
1377 snprintf(fn, sizeof(fn), "digits/%d", num);
1379 } else if (num == 98) {
1380 snprintf(fn, sizeof(fn), "digits/%d", num);
1382 } else if (num < 100) {
1383 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1384 num -= ((num / 10) * 10);
1387 if ((num / 100) > 1) {
1388 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1391 snprintf(fn, sizeof(fn), "digits/hundred");
1393 num -= ((num / 100) * 100);
1395 if (num < 1000000) { /* 1,000,000 */
1397 res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1402 if ((tempnum / 1000) < 2)
1403 snprintf(fn, sizeof(fn), "digits/thousand");
1404 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1405 snprintf(fn, sizeof(fn), "digits/thousands");
1407 if (num < 1000000000) { /* 1,000,000,000 */
1408 if ((num / 1000000) > 1)
1409 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1413 num = num % 1000000;
1414 if ((tempnum / 1000000) < 2)
1415 snprintf(fn, sizeof(fn), "digits/million");
1417 snprintf(fn, sizeof(fn), "digits/millions");
1419 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1426 if(!ast_streamfile(chan, fn, language)) {
1427 if ((audiofd > -1) && (ctrlfd > -1))
1428 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1430 res = ast_waitstream(chan, ints);
1432 ast_stopstream(chan);
1438 /*--- ast_say_number_full_nl: dutch syntax */
1439 /* New files: digits/nl-en
1441 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1448 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1449 while (!res && (num || playh )) {
1451 snprintf(fn, sizeof(fn), "digits/minus");
1452 if ( num > INT_MIN ) {
1458 snprintf(fn, sizeof(fn), "digits/hundred");
1460 } else if (num < 20) {
1461 snprintf(fn, sizeof(fn), "digits/%d", num);
1463 } else if (num < 100) {
1466 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1470 snprintf(fn, sizeof(fn), "digits/nl-en");
1472 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1477 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1479 num -= ((num / 100) * 100);
1481 if (num < 1000000) { /* 1,000,000 */
1482 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
1486 snprintf(fn, sizeof(fn), "digits/thousand");
1488 if (num < 1000000000) { /* 1,000,000,000 */
1489 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1492 num = num % 1000000;
1493 snprintf(fn, sizeof(fn), "digits/million");
1495 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1503 if(!ast_streamfile(chan, fn, language)) {
1504 if ((audiofd > -1) && (ctrlfd > -1))
1505 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1507 res = ast_waitstream(chan, ints);
1509 ast_stopstream(chan);
1515 /*--- ast_say_number_full_no: Norwegian syntax */
1517 In addition to American English, the following sounds are required: "and", "1N"
1519 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)
1524 int cn = 1; /* +1 = commune; -1 = neuter */
1528 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1530 if (options && !strncasecmp(options, "n",1)) cn = -1;
1532 while(!res && (num || playh || playa )) {
1533 /* The grammar for Norwegian numbers is the same as for English except
1534 * for the following:
1535 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1536 * "and" before the last two digits, i.e. 2034 is "two thousand and
1537 * thirty-four" and 1000012 is "one million and twelve".
1540 snprintf(fn, sizeof(fn), "digits/minus");
1541 if ( num > INT_MIN ) {
1547 snprintf(fn, sizeof(fn), "digits/hundred");
1550 snprintf(fn, sizeof(fn), "digits/and");
1552 } else if (num == 1 && cn == -1) {
1553 snprintf(fn, sizeof(fn), "digits/1N");
1555 } else if (num < 20) {
1556 snprintf(fn, sizeof(fn), "digits/%d", num);
1558 } else if (num < 100) {
1559 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1560 num -= ((num / 10) * 10);
1561 } else if (num < 1000) {
1562 int hundreds = num / 100;
1564 snprintf(fn, sizeof(fn), "digits/1N");
1566 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1569 num -= 100 * hundreds;
1572 } else if (num < 1000000) {
1573 res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1576 snprintf(fn, sizeof(fn), "digits/thousand");
1578 if (num && num < 100)
1580 } else if (num < 1000000000) {
1581 int millions = num / 1000000;
1582 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1585 snprintf(fn, sizeof(fn), "digits/million");
1586 num = num % 1000000;
1587 if (num && num < 100)
1590 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1595 if(!ast_streamfile(chan, fn, language)) {
1596 if ((audiofd > -1) && (ctrlfd > -1))
1597 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1599 res = ast_waitstream(chan, ints);
1601 ast_stopstream(chan);
1608 char *separator_dziesiatek;
1612 char *dziesiatki[10];
1617 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1623 return odm->rzedy[rzad - 1][0];
1624 if ((i > 21 || i < 11) && i%10 > 1 && i%10 < 5)
1625 return odm->rzedy[rzad - 1][1];
1627 return odm->rzedy[rzad - 1][2];
1630 static char* pl_append(char* buffer, char* str)
1632 strcpy(buffer, str);
1633 buffer += strlen(str);
1637 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1639 char file_name[255] = "digits/";
1640 strcat(file_name, fn);
1641 ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
1642 if (!ast_streamfile(chan, file_name, language)) {
1643 if ((audiofd > -1) && (ctrlfd > -1))
1644 ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1646 ast_waitstream(chan, ints);
1648 ast_stopstream(chan);
1651 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1653 /* Initialise variables to allow compilation on Debian-stable, etc */
1663 if (i == 0 && rzad > 0) {
1667 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1670 m1000E6 = i % 1000000000;
1671 i1000E6 = i / 1000000000;
1673 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1675 m1000E3 = m1000E6 % 1000000;
1676 i1000E3 = m1000E6 / 1000000;
1678 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1680 m1000 = m1000E3 % 1000;
1681 i1000 = m1000E3 / 1000;
1683 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1689 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1691 if ( m100 > 0 && m100 <=9 ) {
1693 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1695 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1696 } else if (m100 % 10 == 0) {
1697 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1698 } else if (m100 <= 19 ) {
1699 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1700 } else if (m100 != 0) {
1701 if (odm->separator_dziesiatek[0]==' ') {
1702 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1703 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1707 b = pl_append(b, odm->dziesiatki[m100 / 10]);
1708 b = pl_append(b, odm->separator_dziesiatek);
1709 b = pl_append(b, odm->cyfry2[m100 % 10]);
1710 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1715 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1719 /* ast_say_number_full_pl: Polish syntax */
1720 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)
1730 1000000000.2 miliardy
1731 1000000000.5 miliardow
1795 70m siedemdziesieciu
1807 90m dziewiedziesieciu
1809 and combinations of eg.: 20_1, 30m_3m, etc...
1813 char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1815 char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1817 char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1819 char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1821 char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1823 char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1825 char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1827 char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1829 char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1831 char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1833 char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1835 char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1837 char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}};
1839 /* Initialise variables to allow compilation on Debian-stable, etc */
1842 static odmiana *odmiana_nieosobowa = NULL;
1843 static odmiana *odmiana_meska = NULL;
1844 static odmiana *odmiana_zenska = NULL;
1846 if (odmiana_nieosobowa == NULL) {
1847 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
1849 odmiana_nieosobowa->separator_dziesiatek = "_";
1851 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1852 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1853 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1854 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1855 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1856 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1859 if (odmiana_zenska == NULL) {
1860 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
1862 odmiana_zenska->separator_dziesiatek = " ";
1864 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
1865 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
1866 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
1867 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
1868 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
1869 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
1872 if (odmiana_meska == NULL) {
1873 odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
1875 odmiana_meska->separator_dziesiatek = " ";
1877 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
1878 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
1879 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
1880 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
1881 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
1882 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
1886 if (strncasecmp(options, "f", 1) == 0)
1888 else if (strncasecmp(options, "m", 1) == 0)
1891 o = odmiana_nieosobowa;
1893 o = odmiana_nieosobowa;
1895 powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
1899 /* ast_say_number_full_pt: Portuguese syntax */
1900 /* Extra sounds needed: */
1901 /* For feminin all sound files end with F */
1902 /* 100E for 100+ something */
1903 /* 1000000S for plural */
1904 /* pt-e for 'and' */
1905 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)
1909 int mf = 1; /* +1 = male; -1 = female */
1913 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1915 if (options && !strncasecmp(options, "f",1))
1918 while(!res && num ) {
1920 snprintf(fn, sizeof(fn), "digits/minus");
1921 if ( num > INT_MIN ) {
1926 } else if (num < 20) {
1927 if ((num == 1 || num == 2) && (mf < 0))
1928 snprintf(fn, sizeof(fn), "digits/%dF", num);
1930 snprintf(fn, sizeof(fn), "digits/%d", num);
1932 } else if (num < 100) {
1933 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
1937 } else if (num < 1000) {
1939 snprintf(fn, sizeof(fn), "digits/100");
1941 snprintf(fn, sizeof(fn), "digits/100E");
1943 if (mf < 0 && num > 199)
1944 snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
1946 snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
1951 } else if (num < 1000000) {
1953 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
1957 snprintf(fn, sizeof(fn), "digits/1000");
1958 if ((num % 1000) && ((num % 1000) < 100 || !(num % 100)))
1961 } else if (num < 1000000000) {
1962 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
1966 snprintf(fn, sizeof(fn), "digits/1000000");
1968 snprintf(fn, sizeof(fn), "digits/1000000S");
1970 if ((num % 1000000) &&
1972 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
1973 /* no hundreds and below */
1974 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
1976 num = num % 1000000;
1979 if (!ast_streamfile(chan, fn, language)) {
1980 if ((audiofd > -1) && (ctrlfd > -1))
1981 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1983 res = ast_waitstream(chan, ints);
1985 ast_stopstream(chan);
1987 if (!res && playh) {
1988 res = wait_file(chan, ints, "digits/pt-e", language);
1989 ast_stopstream(chan);
1996 /*--- ast_say_number_full_se: Swedish syntax */
1997 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)
2002 int cn = 1; /* +1 = commune; -1 = neuter */
2004 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2005 if (options && !strncasecmp(options, "n",1)) cn = -1;
2007 while(!res && (num || playh)) {
2009 snprintf(fn, sizeof(fn), "digits/minus");
2010 if ( num > INT_MIN ) {
2016 snprintf(fn, sizeof(fn), "digits/hundred");
2018 } else if (num < 20) {
2019 snprintf(fn, sizeof(fn), "digits/%d", num);
2021 } else if (num < 100) {
2022 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2023 num -= ((num / 10) * 10);
2024 } else if (num == 1 && cn == -1) { /* En eller ett? */
2025 snprintf(fn, sizeof(fn), "digits/1N");
2029 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2031 num -= ((num / 100) * 100);
2033 if (num < 1000000) { /* 1,000,000 */
2034 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2039 snprintf(fn, sizeof(fn), "digits/thousand");
2041 if (num < 1000000000) { /* 1,000,000,000 */
2042 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2046 num = num % 1000000;
2047 snprintf(fn, sizeof(fn), "digits/million");
2049 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2056 if(!ast_streamfile(chan, fn, language)) {
2057 if ((audiofd > -1) && (ctrlfd > -1))
2058 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2060 res = ast_waitstream(chan, ints);
2061 ast_stopstream(chan);
2068 /*--- ast_say_number_full_tw: Taiwanese syntax */
2069 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2075 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2077 while(!res && (num || playh)) {
2079 snprintf(fn, sizeof(fn), "digits/minus");
2080 if ( num > INT_MIN ) {
2086 snprintf(fn, sizeof(fn), "digits/hundred");
2088 } else if (num < 10) {
2089 snprintf(fn, sizeof(fn), "digits/%d", num);
2091 } else if (num < 100) {
2092 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2093 num -= ((num / 10) * 10);
2096 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2098 num -= ((num / 100) * 100);
2100 if (num < 1000000) { /* 1,000,000 */
2101 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
2105 snprintf(fn, sizeof(fn), "digits/thousand");
2107 if (num < 1000000000) { /* 1,000,000,000 */
2108 res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2111 num = num % 1000000;
2112 snprintf(fn, sizeof(fn), "digits/million");
2114 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2121 if(!ast_streamfile(chan, fn, language)) {
2122 if ((audiofd > -1) && (ctrlfd > -1))
2123 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2125 res = ast_waitstream(chan, ints);
2127 ast_stopstream(chan);
2133 /*--- ast_say_enumeration_full: call language-specific functions */
2134 /* Called from AGI */
2135 int ast_say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2137 if (!strcasecmp(language,"en") ) { /* English syntax */
2138 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2139 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
2140 return(ast_say_enumeration_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
2141 } else if (!strcasecmp(language, "de") ) { /* German syntax */
2142 return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2145 /* Default to english */
2146 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2149 /*--- ast_say_enumeration: call language-specific functions without file descriptors */
2150 int ast_say_enumeration(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
2152 return(ast_say_enumeration_full(chan, num, ints, language, options, -1, -1));
2155 /*--- ast_say_enumeration_full_en: English syntax */
2156 /* This is the default syntax, if no other syntax defined in this file is used */
2157 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2162 while(!res && num) {
2164 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2165 if ( num > INT_MIN ) {
2170 } else if (num < 20) {
2171 snprintf(fn, sizeof(fn), "digits/h-%d", num);
2173 } else if (num < 100) {
2174 int tens = num / 10;
2177 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2179 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2181 } else if (num < 1000) {
2182 int hundreds = num / 100;
2184 if (hundreds > 1 || t == 1) {
2185 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2190 snprintf(fn, sizeof(fn), "digits/hundred");
2192 snprintf(fn, sizeof(fn), "digits/h-hundred");
2194 } else if (num < 1000000) {
2195 int thousands = num / 1000;
2197 if (thousands > 1 || t == 1) {
2198 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2203 snprintf(fn, sizeof(fn), "digits/thousand");
2205 snprintf(fn, sizeof(fn), "digits/h-thousand");
2208 } else if (num < 1000000000) {
2209 int millions = num / 1000000;
2210 num = num % 1000000;
2212 res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2216 snprintf(fn, sizeof(fn), "digits/million");
2218 snprintf(fn, sizeof(fn), "digits/h-million");
2220 } else if (num < INT_MAX) {
2221 int billions = num / 1000000000;
2222 num = num % 1000000000;
2224 res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2228 snprintf(fn, sizeof(fn), "digits/billion");
2230 snprintf(fn, sizeof(fn), "digits/h-billion");
2232 } else if (num == INT_MAX) {
2233 snprintf(fn, sizeof(fn), "digits/h-last");
2236 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2241 if (!ast_streamfile(chan, fn, language)) {
2242 if ((audiofd > -1) && (ctrlfd > -1)) {
2243 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2245 res = ast_waitstream(chan, ints);
2248 ast_stopstream(chan);
2254 /*--- ast_say_enumeration_full_da: Danish syntax */
2255 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)
2257 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2259 char fn[256] = "", fna[256] = "";
2262 if (options && !strncasecmp(options, "f",1)) {
2264 } else if (options && !strncasecmp(options, "n",1)) {
2271 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2273 while(!res && num) {
2275 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2276 if ( num > INT_MIN ) {
2281 } else if (num < 100 && t) {
2282 snprintf(fn, sizeof(fn), "digits/and");
2284 } else if (num < 20) {
2285 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2287 } else if (num < 100) {
2288 int ones = num % 10;
2290 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2293 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2296 } else if (num == 100 && t == 0) {
2297 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2299 } else if (num < 1000) {
2300 int hundreds = num / 100;
2302 if (hundreds == 1) {
2303 snprintf(fn, sizeof(fn), "digits/1N");
2305 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2308 snprintf(fna, sizeof(fna), "digits/hundred");
2310 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2313 } else if (num < 1000000) {
2314 int thousands = num / 1000;
2316 if (thousands == 1) {
2318 snprintf(fn, sizeof(fn), "digits/1N");
2319 snprintf(fna, sizeof(fna), "digits/thousand");
2322 snprintf(fn, sizeof(fn), "digits/1N");
2323 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2325 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2329 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2334 snprintf(fn, sizeof(fn), "digits/thousand");
2336 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2340 } else if (num < 1000000000) {
2341 int millions = num / 1000000;
2342 num = num % 1000000;
2343 if (millions == 1) {
2345 snprintf(fn, sizeof(fn), "digits/1F");
2346 snprintf(fna, sizeof(fna), "digits/million");
2348 snprintf(fn, sizeof(fn), "digits/1N");
2349 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2352 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2357 snprintf(fn, sizeof(fn), "digits/millions");
2359 snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2363 } else if (num < INT_MAX) {
2364 int billions = num / 1000000000;
2365 num = num % 1000000000;
2366 if (billions == 1) {
2368 snprintf(fn, sizeof(fn), "digits/1F");
2369 snprintf(fna, sizeof(fna), "digits/milliard");
2371 snprintf(fn, sizeof(fn), "digits/1N");
2372 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2375 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2379 snprintf(fn, sizeof(fna), "digits/milliards");
2381 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2385 } else if (num == INT_MAX) {
2386 snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2389 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2394 if (!ast_streamfile(chan, fn, language)) {
2395 if ((audiofd > -1) && (ctrlfd > -1))
2396 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2398 res = ast_waitstream(chan, ints);
2400 ast_stopstream(chan);
2402 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2403 if ((audiofd > -1) && (ctrlfd > -1)) {
2404 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2406 res = ast_waitstream(chan, ints);
2409 ast_stopstream(chan);
2417 /*--- ast_say_enumeration_full_de: German syntax */
2418 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)
2420 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2422 char fn[256] = "", fna[256] = "";
2425 if (options && !strncasecmp(options, "f",1)) {
2427 } else if (options && !strncasecmp(options, "n",1)) {
2434 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2436 while(!res && num) {
2438 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2439 if ( num > INT_MIN ) {
2444 } else if (num < 100 && t) {
2445 snprintf(fn, sizeof(fn), "digits/and");
2447 } else if (num < 20) {
2448 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2450 } else if (num < 100) {
2451 int ones = num % 10;
2453 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2456 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2459 } else if (num == 100 && t == 0) {
2460 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2462 } else if (num < 1000) {
2463 int hundreds = num / 100;
2465 if (hundreds == 1) {
2466 snprintf(fn, sizeof(fn), "digits/1N");
2468 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2471 snprintf(fna, sizeof(fna), "digits/hundred");
2473 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2476 } else if (num < 1000000) {
2477 int thousands = num / 1000;
2479 if (thousands == 1) {
2481 snprintf(fn, sizeof(fn), "digits/1N");
2482 snprintf(fna, sizeof(fna), "digits/thousand");
2485 snprintf(fn, sizeof(fn), "digits/1N");
2486 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2488 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2492 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2497 snprintf(fn, sizeof(fn), "digits/thousand");
2499 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2503 } else if (num < 1000000000) {
2504 int millions = num / 1000000;
2505 num = num % 1000000;
2506 if (millions == 1) {
2508 snprintf(fn, sizeof(fn), "digits/1F");
2509 snprintf(fna, sizeof(fna), "digits/million");
2511 snprintf(fn, sizeof(fn), "digits/1N");
2512 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2515 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2520 snprintf(fn, sizeof(fn), "digits/millions");
2522 snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2526 } else if (num < INT_MAX) {
2527 int billions = num / 1000000000;
2528 num = num % 1000000000;
2529 if (billions == 1) {
2531 snprintf(fn, sizeof(fn), "digits/1F");
2532 snprintf(fna, sizeof(fna), "digits/milliard");
2534 snprintf(fn, sizeof(fn), "digits/1N");
2535 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2538 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2542 snprintf(fn, sizeof(fna), "digits/milliards");
2544 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2548 } else if (num == INT_MAX) {
2549 snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2552 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2557 if (!ast_streamfile(chan, fn, language)) {
2558 if ((audiofd > -1) && (ctrlfd > -1))
2559 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2561 res = ast_waitstream(chan, ints);
2563 ast_stopstream(chan);
2565 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2566 if ((audiofd > -1) && (ctrlfd > -1)) {
2567 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2569 res = ast_waitstream(chan, ints);
2572 ast_stopstream(chan);
2580 int ast_say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2582 if (!strcasecmp(lang, "en") ) { /* English syntax */
2583 return(ast_say_date_en(chan, t, ints, lang));
2584 } else if (!strcasecmp(lang, "da") ) { /* Danish syntax */
2585 return(ast_say_date_da(chan, t, ints, lang));
2586 } else if (!strcasecmp(lang, "de") ) { /* German syntax */
2587 return(ast_say_date_de(chan, t, ints, lang));
2588 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */
2589 return(ast_say_date_fr(chan, t, ints, lang));
2590 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */
2591 return(ast_say_date_nl(chan, t, ints, lang));
2592 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */
2593 return(ast_say_date_pt(chan, t, ints, lang));
2594 } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */
2595 return(ast_say_date_gr(chan, t, ints, lang));
2598 /* Default to English */
2599 return(ast_say_date_en(chan, t, ints, lang));
2602 /* English syntax */
2603 int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2608 ast_localtime(&t,&tm,NULL);
2610 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2611 res = ast_streamfile(chan, fn, lang);
2613 res = ast_waitstream(chan, ints);
2616 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2617 res = ast_streamfile(chan, fn, lang);
2619 res = ast_waitstream(chan, ints);
2622 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2624 res = ast_waitstream(chan, ints);
2626 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2631 int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2636 ast_localtime(&t,&tm,NULL);
2638 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2639 res = ast_streamfile(chan, fn, lang);
2641 res = ast_waitstream(chan, ints);
2644 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2646 res = ast_waitstream(chan, ints);
2648 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2649 res = ast_streamfile(chan, fn, lang);
2651 res = ast_waitstream(chan, ints);
2655 int year = tm.tm_year + 1900;
2656 if (year > 1999) { /* year 2000 and later */
2657 res = ast_say_number(chan, year, ints, lang, (char *) NULL);
2660 /* I'm not going to handle 1100 and prior */
2661 /* We'll just be silent on the year, instead of bombing out. */
2663 /* year 1100 to 1999. will anybody need this?!? */
2664 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) );
2665 res = wait_file(chan, ints, fn, lang);
2667 res = wait_file(chan,ints, "digits/hundred", lang);
2668 if (!res && year % 100 != 0) {
2669 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
2679 int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2684 ast_localtime(&t,&tm,NULL);
2686 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2687 res = ast_streamfile(chan, fn, lang);
2689 res = ast_waitstream(chan, ints);
2692 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2694 res = ast_waitstream(chan, ints);
2696 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2697 res = ast_streamfile(chan, fn, lang);
2699 res = ast_waitstream(chan, ints);
2703 int year = tm.tm_year + 1900;
2704 if (year > 1999) { /* year 2000 and later */
2705 res = ast_say_number(chan, year, ints, lang, (char *) NULL);
2708 /* I'm not going to handle 1100 and prior */
2709 /* We'll just be silent on the year, instead of bombing out. */
2711 /* year 1100 to 1999. will anybody need this?!? */
2712 /* say 1967 as 'neunzehn hundert sieben und sechzig' */
2713 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) );
2714 res = wait_file(chan, ints, fn, lang);
2716 res = wait_file(chan,ints, "digits/hundred", lang);
2717 if (!res && year % 100 != 0) {
2718 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
2728 int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2733 ast_localtime(&t,&tm,NULL);
2735 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2736 res = ast_streamfile(chan, fn, lang);
2738 res = ast_waitstream(chan, ints);
2741 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2743 res = ast_waitstream(chan, ints);
2745 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2746 res = ast_streamfile(chan, fn, lang);
2748 res = ast_waitstream(chan, ints);
2751 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2756 int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2761 ast_localtime(&t,&tm,NULL);
2763 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2764 res = ast_streamfile(chan, fn, lang);
2766 res = ast_waitstream(chan, ints);
2769 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2771 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2772 res = ast_streamfile(chan, fn, lang);
2774 res = ast_waitstream(chan, ints);
2777 res = ast_waitstream(chan, ints);
2779 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2783 /* Portuguese syntax */
2784 int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2789 ast_localtime(&t,&tm,NULL);
2790 localtime_r(&t,&tm);
2791 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2793 res = wait_file(chan, ints, fn, lang);
2795 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
2797 res = wait_file(chan, ints, "digits/pt-de", lang);
2798 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2800 res = wait_file(chan, ints, fn, lang);
2802 res = wait_file(chan, ints, "digits/pt-de", lang);
2804 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2809 int ast_say_date_with_format(struct ast_channel *chan, time_t time, const char *ints, const char *lang, const char *format, const char *timezone)
2811 if (!strcasecmp(lang, "en") ) { /* English syntax */
2812 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2813 } else if (!strcasecmp(lang, "da") ) { /* Danish syntax */
2814 return(ast_say_date_with_format_da(chan, time, ints, lang, format, timezone));
2815 } else if (!strcasecmp(lang, "de") ) { /* German syntax */
2816 return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone));
2817 } else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) { /* Spanish syntax */
2818 return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone));
2819 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */
2820 return(ast_say_date_with_format_fr(chan, time, ints, lang, format, timezone));
2821 } else if (!strcasecmp(lang, "it") ) { /* Italian syntax */
2822 return(ast_say_date_with_format_it(chan, time, ints, lang, format, timezone));
2823 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */
2824 return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone));
2825 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */
2826 return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone));
2827 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */
2828 return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone));
2829 } else if (!strcasecmp(lang, "gr") ) { /* Greek syntax */
2830 return(ast_say_date_with_format_gr(chan, time, ints, lang, format, timezone));
2833 /* Default to English */
2834 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2837 /* English syntax */
2838 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)
2841 int res=0, offset, sndoffset;
2842 char sndfile[256], nextmsg[256];
2844 ast_localtime(&time,&tm,timezone);
2846 for (offset=0 ; format[offset] != '\0' ; offset++) {
2847 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
2848 switch (format[offset]) {
2849 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
2851 /* Literal name of a sound file */
2853 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
2854 sndfile[sndoffset] = format[offset];
2855 sndfile[sndoffset] = '\0';
2856 res = wait_file(chan,ints,sndfile,lang);
2860 /* Sunday - Saturday */
2861 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
2862 res = wait_file(chan,ints,nextmsg,lang);
2867 /* January - December */
2868 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
2869 res = wait_file(chan,ints,nextmsg,lang);
2872 /* Month enumerated */
2873 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, (char *) NULL);
2877 /* First - Thirtyfirst */
2878 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char *) NULL);
2882 if (tm.tm_year > 99) {
2883 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2885 if (tm.tm_year < 1) {
2886 /* I'm not going to handle 1900 and prior */
2887 /* We'll just be silent on the year, instead of bombing out. */
2889 res = wait_file(chan,ints, "digits/19",lang);
2891 if (tm.tm_year <= 9) {
2893 res = wait_file(chan,ints, "digits/oh",lang);
2895 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2896 res = wait_file(chan,ints,nextmsg,lang);
2898 } else if (tm.tm_year <= 20) {
2900 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2901 res = wait_file(chan,ints,nextmsg,lang);
2905 ten = tm.tm_year / 10;
2906 one = tm.tm_year % 10;
2907 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
2908 res = wait_file(chan,ints,nextmsg,lang);
2911 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2912 res = wait_file(chan,ints,nextmsg,lang);
2923 if (tm.tm_hour == 0)
2924 snprintf(nextmsg,sizeof(nextmsg), "digits/12");
2925 else if (tm.tm_hour > 12)
2926 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
2928 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
2929 res = wait_file(chan,ints,nextmsg,lang);
2934 if (format[offset] == 'H') {
2936 if (tm.tm_hour < 10) {
2937 res = wait_file(chan,ints, "digits/oh",lang);
2941 if (tm.tm_hour == 0) {
2942 res = wait_file(chan,ints, "digits/oh",lang);
2946 if (tm.tm_hour != 0) {
2947 int remainder = tm.tm_hour;
2948 if (tm.tm_hour > 20) {
2949 res = wait_file(chan,ints, "digits/20",lang);
2953 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
2954 res = wait_file(chan,ints,nextmsg,lang);
2961 if (tm.tm_min == 0) {
2962 res = wait_file(chan,ints, "digits/oclock",lang);
2963 } else if (tm.tm_min < 10) {
2964 res = wait_file(chan,ints, "digits/oh",lang);
2966 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2967 res = wait_file(chan,ints,nextmsg,lang);
2969 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
2970 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2971 res = wait_file(chan,ints,nextmsg,lang);
2974 ten = (tm.tm_min / 10) * 10;
2975 one = (tm.tm_min % 10);
2976 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2977 res = wait_file(chan,ints,nextmsg,lang);
2979 /* Fifty, not fifty-zero */
2981 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2982 res = wait_file(chan,ints,nextmsg,lang);
2990 if (tm.tm_hour > 11)
2991 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
2993 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
2994 res = wait_file(chan,ints,nextmsg,lang);
2997 /* Shorthand for "Today", "Yesterday", or ABdY */
3003 gettimeofday(&now,NULL);
3004 ast_localtime(&now.tv_sec,&tmnow,timezone);
3005 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3006 /* In any case, it saves not having to do ast_mktime() */
3007 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
3008 if (beg_today < time) {
3010 res = wait_file(chan,ints, "digits/today",lang);
3011 } else if (beg_today - 86400 < time) {
3013 res = wait_file(chan,ints, "digits/yesterday",lang);
3015 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
3020 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
3026 gettimeofday(&now,NULL);
3027 ast_localtime(&now.tv_sec,&tmnow,timezone);
3028 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
3029 /* In any case, it saves not having to do ast_mktime() */
3030 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
3031 if (beg_today < time) {
3033 } else if ((beg_today - 86400) < time) {
3035 res = wait_file(chan,ints, "digits/yesterday",lang);
3036 } else if (beg_today - 86400 * 6 < time) {
3037 /* Within the last week */
3038 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
3040 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
3045 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
3049 if (tm.tm_sec == 0) {
3050 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
3051 res = wait_file(chan,ints,nextmsg,lang);
3052 } else if (tm.tm_sec < 10) {
3053 res = wait_file(chan,ints, "digits/oh",lang);
3055 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
3056 res = wait_file(chan,ints,nextmsg,lang);
3058 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
3059 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
3060 res = wait_file(chan,ints,nextmsg,lang);
3063 ten = (tm.tm_sec / 10) * 10;
3064 one = (tm.tm_sec % 10);
3065 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
3066 res = wait_file(chan,ints,nextmsg,lang);
3068 /* Fifty, not fifty-zero */
3070 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
3071 res = wait_file(chan,ints,nextmsg,lang);
3077 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);