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
14 #include <sys/types.h>
17 #include <netinet/in.h>
21 #include <asterisk/file.h>
22 #include <asterisk/channel.h>
23 #include <asterisk/logger.h>
24 #include <asterisk/say.h>
25 #include <asterisk/lock.h>
26 #include <asterisk/localtime.h>
27 #include <asterisk/utils.h>
32 /* Forward declaration */
33 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
35 int ast_say_digit_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
37 /* XXX Merge with full version? XXX */
41 while(fn2[num] && !res) {
45 snprintf(fn, sizeof(fn), "digits/star");
48 snprintf(fn, sizeof(fn), "digits/pound");
51 if((fn2[num] >= '0') && (fn2[num] <= '9')){ /* Must be in {0-9} */
52 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
55 if(!ast_strlen_zero(fn)){ /* if length == 0, then skip this digit as it is invalid */
56 res = ast_streamfile(chan, fn, lang);
58 res = ast_waitstream(chan, ints);
66 int ast_say_character_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
68 /* XXX Merge with full version? XXX */
73 while(fn2[num] && !res) {
77 snprintf(fn, sizeof(fn), "digits/star");
80 snprintf(fn, sizeof(fn), "digits/pound");
92 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
95 strncpy(fn, "letters/exclaimation-point", sizeof(fn));
98 strncpy(fn, "letters/at", sizeof(fn));
101 strncpy(fn, "letters/dollar", sizeof(fn));
104 strncpy(fn, "letters/dash", sizeof(fn));
107 strncpy(fn, "letters/dot", sizeof(fn));
110 strncpy(fn, "letters/equals", sizeof(fn));
113 strncpy(fn, "letters/plus", sizeof(fn));
116 strncpy(fn, "letters/slash", sizeof(fn));
119 strncpy(fn, "letters/space", sizeof(fn));
123 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
124 snprintf(fn, sizeof(fn), "letters/%c", ltr);
126 if(!ast_strlen_zero(fn)) { /* if length == 0, then skip this digit as it is invalid */
127 res = ast_streamfile(chan, fn, lang);
129 res = ast_waitstream(chan, ints);
130 } ast_stopstream(chan);
136 int ast_say_phonetic_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
138 /* XXX Merge with full version? XXX */
146 /* while(fn2[num] && !res) { */
151 snprintf(fn, sizeof(fn), "digits/star");
154 snprintf(fn, sizeof(fn), "digits/pound");
165 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
168 strncpy(fn, "exclaimation-point", sizeof(fn));
171 strncpy(fn, "at", sizeof(fn));
174 strncpy(fn, "dollar", sizeof(fn));
177 strncpy(fn, "dash", sizeof(fn));
180 strncpy(fn, "dot", sizeof(fn));
183 strncpy(fn, "equals", sizeof(fn));
186 strncpy(fn, "plus", sizeof(fn));
189 strncpy(fn, "slash", sizeof(fn));
192 strncpy(fn, "space", sizeof(fn));
196 /* check if we have 2 chars after the % */
197 if (strlen(fn2) > num+2)
202 if (sscanf(hex,"%x", &temp))
203 { /* Hex to char convertion successfull */
206 { /* If it is a percent, play it now */
207 strncpy(fn, "percent", sizeof(fn));
211 /* check for invalid characters */
212 if ((temp<32) || (temp>126))
221 default: /* '9' falls through to here, too */
222 ltr = tolower(fn2[num]);
223 snprintf(fn, sizeof(fn), "phonetic/%c_p", ltr);
227 res = ast_streamfile(chan, fn, lang);
229 res = ast_waitstream(chan, ints);
230 ast_stopstream(chan);
237 int ast_say_digit_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
242 while(fn2[num] && !res) {
243 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
244 res = ast_streamfile(chan, fn, lang);
246 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
247 ast_stopstream(chan);
253 int ast_say_character_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
259 while(fn2[num] && !res) {
262 snprintf(fn, sizeof(fn), "digits/star");
265 snprintf(fn, sizeof(fn), "digits/pound");
277 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
280 strncpy(fn, "exclaimation-point", sizeof(fn));
283 strncpy(fn, "at", sizeof(fn));
286 strncpy(fn, "dollar", sizeof(fn));
289 strncpy(fn, "dash", sizeof(fn));
292 strncpy(fn, "dot", sizeof(fn));
295 strncpy(fn, "equals", sizeof(fn));
298 strncpy(fn, "plus", sizeof(fn));
301 strncpy(fn, "slash", sizeof(fn));
304 strncpy(fn, "space", sizeof(fn));
308 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
309 snprintf(fn, sizeof(fn), "letters/%c", ltr);
311 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
312 res = ast_streamfile(chan, fn, lang);
314 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
315 ast_stopstream(chan);
321 int ast_say_phonetic_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
327 while(fn2[num] && !res) {
330 snprintf(fn, sizeof(fn), "digits/star");
333 snprintf(fn, sizeof(fn), "digits/pound");
344 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
347 strncpy(fn, "exclaimation-point", sizeof(fn));
350 strncpy(fn, "at", sizeof(fn));
353 strncpy(fn, "dollar", sizeof(fn));
356 strncpy(fn, "dash", sizeof(fn));
359 strncpy(fn, "dot", sizeof(fn));
362 strncpy(fn, "equals", sizeof(fn));
365 strncpy(fn, "plus", sizeof(fn));
368 strncpy(fn, "slash", sizeof(fn));
371 strncpy(fn, "space", sizeof(fn));
373 default: /* '9' falls here... */
375 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A'; /* file names are all lower-case */
376 snprintf(fn, sizeof(fn), "phonetic/%c", ltr);
378 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
379 res = ast_streamfile(chan, fn, lang);
381 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
382 ast_stopstream(chan);
388 int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
390 /* XXX Should I be merged with say_digits_full XXX */
392 snprintf(fn2, sizeof(fn2), "%d", num);
393 return ast_say_digit_str(chan, fn2, ints, lang);
396 int ast_say_digits_full(struct ast_channel *chan, int num, const char *ints, const char *lang, int audiofd, int ctrlfd)
399 snprintf(fn2, sizeof(fn2), "%d", num);
400 return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
403 /* Forward declarations */
404 /* Syntaxes supported, not really language codes.
408 en_GB - English (British)
409 es - Spanish, Mexican
420 For Some languages the numbers differ for gender and plural
421 Use the option argument 'f' for female, 'm' for male and 'n' for neuter in languages like Portuguese, French, Spanish and German.
422 use the option argument 'c' is for commune and 'n' for neuter gender in nordic languages like Danish, Swedish and Norwegian.
423 use the option argument 'p' for plural enumerations like in German
425 Date/Time functions currently have less languages supported than saynumber().
427 Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
429 See contrib/i18n.testsuite.conf for some examples of the different syntaxes
431 Portuguese sound files needed for Time/Date functions:
441 Spanish sound files needed for Time/Date functions:
445 Italian sound files needed for Time/Date functions:
451 /* Forward declarations of language specific variants of ast_say_number_full */
452 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
453 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);
454 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);
455 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);
456 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
457 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);
458 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);
459 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
460 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
461 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);
462 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);
463 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);
464 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);
465 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
467 /* Forward declarations of language specific variants of ast_say_enumeration_full */
468 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd);
469 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);
471 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
472 static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
473 static int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
474 static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
475 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
476 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
478 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);
479 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);
480 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);
481 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);
482 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);
483 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);
484 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);
485 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);
487 static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
488 static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
489 static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
490 static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
491 static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
492 static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
494 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
495 static int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
496 static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
497 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
498 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
499 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
501 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
502 static int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
503 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
505 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang)
508 if ((res = ast_streamfile(chan, file, lang)))
509 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
511 res = ast_waitstream(chan, ints);
515 /*--- ast_say_number_full: call language-specific functions */
516 /* Called from AGI */
517 int ast_say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
519 if (!strcasecmp(language,"en") ) { /* English syntax */
520 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
521 } else if (!strcasecmp(language, "cz") ) { /* Czech syntax */
522 return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd));
523 } else if (!strcasecmp(language, "da") ) { /* Danish syntax */
524 return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
525 } else if (!strcasecmp(language, "de") ) { /* German syntax */
526 return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
527 } else if (!strcasecmp(language, "en_GB") ) { /* British syntax */
528 return(ast_say_number_full_en_GB(chan, num, ints, language, audiofd, ctrlfd));
529 } else if (!strcasecmp(language, "no") ) { /* Norwegian syntax */
530 return(ast_say_number_full_no(chan, num, ints, language, options, audiofd, ctrlfd));
531 } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) { /* Spanish syntax */
532 return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd));
533 } else if (!strcasecmp(language, "fr") ) { /* French syntax */
534 return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd));
535 } else if (!strcasecmp(language, "it") ) { /* Italian syntax */
536 return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd));
537 } else if (!strcasecmp(language, "nl") ) { /* Dutch syntax */
538 return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd));
539 } else if (!strcasecmp(language, "pl") ) { /* Polish syntax */
540 return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd));
541 } else if (!strcasecmp(language, "pt") ) { /* Portuguese syntax */
542 return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd));
543 } else if (!strcasecmp(language, "se") ) { /* Swedish syntax */
544 return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd));
545 } else if (!strcasecmp(language, "tw")) { /* Taiwanese syntax */
546 return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd));
549 /* Default to english */
550 return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
553 /*--- ast_say_number: call language-specific functions without file descriptors */
554 int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
556 return(ast_say_number_full(chan, num, ints, language, options, -1, -1));
559 /*--- ast_say_number_full_en: English syntax */
560 /* This is the default syntax, if no other syntax defined in this file is used */
561 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
567 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
569 while(!res && (num || playh)) {
571 snprintf(fn, sizeof(fn), "digits/minus");
572 if ( num > INT_MIN ) {
578 snprintf(fn, sizeof(fn), "digits/hundred");
580 } else if (num < 20) {
581 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);
588 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
590 num -= ((num / 100) * 100);
592 if (num < 1000000) { /* 1,000,000 */
593 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
597 snprintf(fn, sizeof(fn), "digits/thousand");
599 if (num < 1000000000) { /* 1,000,000,000 */
600 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
604 snprintf(fn, sizeof(fn), "digits/million");
606 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
613 if(!ast_streamfile(chan, fn, language)) {
614 if (audiofd && ctrlfd)
615 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
617 res = ast_waitstream(chan, ints);
619 ast_stopstream(chan);
625 static int exp10_int(int power)
628 for (x=0;x<power;x++)
633 /*--- ast_say_number_full_cz: Czech syntax */
635 * 1m,2m - gender male
636 * 1w,2w - gender female
640 * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set
642 * for each number 10^(3n + 3) exist 3 files represented as:
643 * 1 tousand = jeden tisic = 1_E3
644 * 2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
645 * 5,6,... tousands = pet,sest,... tisic = 5_E3
651 * tousand, milion are gender male, so 1 and 2 is 1m 2m
652 * miliard is gender female, so 1 and 2 is 1w 2w
654 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)
664 /* options - w = woman, m = man, n = neutral. Defaultl is woman */
669 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
671 while(!res && (num || playh)) {
673 snprintf(fn, sizeof(fn), "digits/minus");
674 if ( num > INT_MIN ) {
679 } else if (num < 3 ) {
680 snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]);
683 } else if (num < 20) {
684 snprintf(fn, sizeof(fn), "digits/%d",num);
687 } else if (num < 100) {
688 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
689 num -= ((num / 10) * 10);
690 } else if (num < 1000) {
691 hundered = num / 100;
692 if ( hundered == 1 ) {
693 snprintf(fn, sizeof(fn), "digits/1sto");
694 } else if ( hundered == 2 ) {
695 snprintf(fn, sizeof(fn), "digits/2ste");
697 res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd);
700 if (hundered == 3 || hundered == 4) {
701 snprintf(fn, sizeof(fn), "digits/sta");
702 } else if ( hundered > 4 ) {
703 snprintf(fn, sizeof(fn), "digits/set");
706 num -= (hundered * 100);
707 } else { /* num > 1000 */
708 length = (int)log10(num)+1;
709 while ( (length % 3 ) != 1 ) {
712 left = num / (exp10_int(length-1));
715 case 9: options = "w"; /* 1,000,000,000 gender female */
717 default : options = "m"; /* others are male */
720 if ( left > 1 ) { /* we dont say "one thousand" but only thousand */
721 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd);
725 if ( left >= 5 ) { /* >= 5 have the same declesion */
726 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1);
727 } else if ( left >= 2 && left <= 4 ) {
728 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1);
729 } else { /* left == 1 */
730 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1);
732 num -= left * (exp10_int(length-1));
735 if(!ast_streamfile(chan, fn, language)) {
736 if (audiofd && ctrlfd) {
737 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
739 res = ast_waitstream(chan, ints);
742 ast_stopstream(chan);
748 /*--- ast_say_number_full_da: Danish syntax */
750 In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and"
752 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)
757 int cn = 1; /* +1 = commune; -1 = neuter */
760 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
762 if (options && !strncasecmp(options, "n",1)) cn = -1;
764 while(!res && (num || playh || playa )) {
765 /* The grammar for Danish numbers is the same as for English except
767 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1")
768 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
769 * "one-and twenty" and 68 is "eight-and sixty".
770 * - "million" is different in singular and plural form
771 * - numbers > 1000 with zero as the third digit from last have an
772 * "and" before the last two digits, i.e. 2034 is "two thousand and
773 * four-and thirty" and 1000012 is "one million and twelve".
776 snprintf(fn, sizeof(fn), "digits/minus");
777 if ( num > INT_MIN ) {
783 snprintf(fn, sizeof(fn), "digits/hundred");
786 snprintf(fn, sizeof(fn), "digits/and");
788 } else if (num == 1 && cn == -1) {
789 snprintf(fn, sizeof(fn), "digits/1N");
791 } else if (num < 20) {
792 snprintf(fn, sizeof(fn), "digits/%d", num);
794 } else if (num < 100) {
797 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
800 snprintf(fn, sizeof(fn), "digits/%d", num);
805 int hundreds = num / 100;
807 snprintf(fn, sizeof(fn), "digits/1N");
809 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
812 num -= 100 * hundreds;
818 res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
822 snprintf(fn, sizeof(fn), "digits/thousand");
824 if (num < 1000000000) {
825 int millions = num / 1000000;
826 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
830 snprintf(fn, sizeof(fn), "digits/million");
832 snprintf(fn, sizeof(fn), "digits/millions");
835 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
839 if (num && num < 100)
844 if(!ast_streamfile(chan, fn, language)) {
845 if (audiofd && ctrlfd)
846 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
848 res = ast_waitstream(chan, ints);
850 ast_stopstream(chan);
856 /*--- ast_say_number_full_de: German syntax */
858 In addition to English, the following sounds are required:
860 "1-and" through "9-and"
863 NB "1" is recorded as 'eins'
865 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)
868 int mf = 1; /* +1 = male and neuter; -1 = female */
872 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
874 if (options && (!strncasecmp(options, "f",1)))
878 /* The grammar for German numbers is the same as for English except
880 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
881 * "one-and twenty" and 68 is "eight-and sixty".
882 * - "one" varies according to gender
883 * - 100 is 'hundert', however all other instances are 'ein hundert'
884 * - 1000 is 'tausend', however all other instances are 'ein tausend'
885 * - 1000000 is always 'eine million'
886 * - "million" is different in singular and plural form
889 snprintf(fn, sizeof(fn), "digits/minus");
890 if ( num > INT_MIN ) {
895 } else if (num < 100 && t) {
896 snprintf(fn, sizeof(fn), "digits/and");
898 } else if (num == 1 && mf == -1) {
899 snprintf(fn, sizeof(fn), "digits/%dF", num);
901 } else if (num < 20) {
902 snprintf(fn, sizeof(fn), "digits/%d", num);
904 } else if (num < 100) {
907 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
910 snprintf(fn, sizeof(fn), "digits/%d", num);
913 } else if (num == 100 && t == 0) {
914 snprintf(fn, sizeof(fn), "digits/hundred");
916 } else if (num < 1000) {
917 int hundreds = num / 100;
920 snprintf(fn, sizeof(fn), "digits/1N");
922 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
924 snprintf(fna, sizeof(fna), "digits/hundred");
926 } else if (num == 1000 && t == 0) {
927 snprintf(fn, sizeof(fn), "digits/thousand");
929 } else if (num < 1000000) {
930 int thousands = num / 1000;
933 if (thousands == 1) {
934 snprintf(fn, sizeof(fn), "digits/1N");
935 snprintf(fna, sizeof(fna), "digits/thousand");
937 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
940 snprintf(fn, sizeof(fn), "digits/thousand");
942 } else if (num < 1000000000) {
943 int millions = num / 1000000;
947 snprintf(fn, sizeof(fn), "digits/1F");
948 snprintf(fna, sizeof(fna), "digits/million");
950 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
953 snprintf(fn, sizeof(fn), "digits/millions");
955 } else if (num <= INT_MAX) {
956 int billions = num / 1000000000;
957 num = num % 1000000000;
960 snprintf(fn, sizeof(fn), "digits/1F");
961 snprintf(fna, sizeof(fna), "digits/milliard");
963 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
967 snprintf(fn, sizeof(fn), "digits/milliards");
970 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
974 if(!ast_streamfile(chan, fn, language)) {
975 if (audiofd && ctrlfd)
976 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
978 res = ast_waitstream(chan, ints);
980 ast_stopstream(chan);
982 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
983 if (audiofd && ctrlfd)
984 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
986 res = ast_waitstream(chan, ints);
988 ast_stopstream(chan);
996 /*--- ast_say_number_full_en_GB: British and Norwegian syntax */
998 In addition to American English, the following sounds are required: "and"
1000 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1007 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1009 while(!res && (num || playh || playa )) {
1011 snprintf(fn, sizeof(fn), "digits/minus");
1012 if ( num > INT_MIN ) {
1018 snprintf(fn, sizeof(fn), "digits/hundred");
1021 snprintf(fn, sizeof(fn), "digits/and");
1023 } else if (num < 20) {
1024 snprintf(fn, sizeof(fn), "digits/%d", num);
1026 } else if (num < 100) {
1027 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1028 num -= ((num / 10) * 10);
1029 } else if (num < 1000) {
1030 int hundreds = num / 100;
1031 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1034 num -= 100 * hundreds;
1037 } else if (num < 1000000) {
1038 res = ast_say_number_full_en_GB(chan, num / 1000, ints, language, audiofd, ctrlfd);
1041 snprintf(fn, sizeof(fn), "digits/thousand");
1043 if (num && num < 100)
1045 } else if (num < 1000000000) {
1046 int millions = num / 1000000;
1047 res = ast_say_number_full_en_GB(chan, millions, ints, language, audiofd, ctrlfd);
1050 snprintf(fn, sizeof(fn), "digits/million");
1051 num = num % 1000000;
1052 if (num && num < 100)
1055 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1060 if(!ast_streamfile(chan, fn, language)) {
1061 if (audiofd && ctrlfd)
1062 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1064 res = ast_waitstream(chan, ints);
1066 ast_stopstream(chan);
1072 /*--- ast_say_number_full_es: Spanish syntax */
1074 Requires a few new audios:
1075 1F.gsm: feminine 'una'
1076 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
1078 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)
1082 int mf = 1; /* +1 = male; -1 = female */
1085 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1087 if (options && !strncasecmp(options, "f",1))
1090 while (!res && num) {
1092 snprintf(fn, sizeof(fn), "digits/minus");
1093 if ( num > INT_MIN ) {
1099 snprintf(fn, sizeof(fn), "digits/y");
1101 } else if (num == 1) {
1103 snprintf(fn, sizeof(fn), "digits/%dF", num);
1105 snprintf(fn, sizeof(fn), "digits/%d", num);
1107 } else if (num < 31) {
1108 snprintf(fn, sizeof(fn), "digits/%d", num);
1110 } else if (num < 100) {
1111 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1112 num -= ((num/10)*10);
1115 } else if (num == 100) {
1116 snprintf(fn, sizeof(fn), "digits/cien");
1120 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
1121 num -= ((num/100)*100);
1123 if (num < 1000000) {
1124 res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1128 snprintf(fn, sizeof(fn), "digits/mil");
1130 if (num < 2147483640) {
1131 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1134 if ((num/1000000) == 1) {
1135 snprintf(fn, sizeof(fn), "digits/millon");
1137 snprintf(fn, sizeof(fn), "digits/millones");
1139 num = num % 1000000;
1141 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1149 if(!ast_streamfile(chan, fn, language)) {
1150 if (audiofd && ctrlfd)
1151 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1153 res = ast_waitstream(chan, ints);
1155 ast_stopstream(chan);
1163 /*--- ast_say_number_full_fr: French syntax */
1164 /* Extra sounds needed:
1167 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)
1172 int mf = 1; /* +1 = male; -1 = female */
1175 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1177 if (options && !strncasecmp(options, "f",1))
1180 while(!res && (num || playh || playa)) {
1182 snprintf(fn, sizeof(fn), "digits/minus");
1183 if ( num > INT_MIN ) {
1189 snprintf(fn, sizeof(fn), "digits/hundred");
1192 snprintf(fn, sizeof(fn), "digits/et");
1194 } else if (num == 1) {
1196 snprintf(fn, sizeof(fn), "digits/%dF", num);
1198 snprintf(fn, sizeof(fn), "digits/%d", num);
1200 } else if (num < 21) {
1201 snprintf(fn, sizeof(fn), "digits/%d", num);
1203 } else if (num < 70) {
1204 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1205 if ((num % 10) == 1) playa++;
1207 } else if (num < 80) {
1208 snprintf(fn, sizeof(fn), "digits/60");
1209 if ((num % 10) == 1) playa++;
1211 } else if (num < 100) {
1212 snprintf(fn, sizeof(fn), "digits/80");
1214 } else if (num < 200) {
1215 snprintf(fn, sizeof(fn), "digits/hundred");
1217 } else if (num < 1000) {
1218 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1221 } else if (num < 2000) {
1222 snprintf(fn, sizeof(fn), "digits/thousand");
1224 } else if (num < 1000000) {
1225 res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1228 snprintf(fn, sizeof(fn), "digits/thousand");
1230 } else if (num < 1000000000) {
1231 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1234 snprintf(fn, sizeof(fn), "digits/million");
1235 num = num % 1000000;
1237 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1241 if(!ast_streamfile(chan, fn, language)) {
1242 if (audiofd && ctrlfd)
1243 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1245 res = ast_waitstream(chan, ints);
1247 ast_stopstream(chan);
1253 /*--- ast_say_number_full_it: Italian */
1254 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1262 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1267 Like english, numbers up to 20 are a single 'word', and others
1268 compound, but with exceptions.
1269 For example 21 is not twenty-one, but there is a single word in 'it'.
1270 Idem for 28 (ie when a the 2nd part of a compund number
1271 starts with a vowel)
1273 There are exceptions also for hundred, thousand and million.
1274 In english 100 = one hundred, 200 is two hundred.
1275 In italian 100 = cento , like to say hundred (without one),
1276 200 and more are like english.
1278 Same applies for thousand:
1279 1000 is one thousand in en, 2000 is two thousand.
1280 In it we have 1000 = mille , 2000 = 2 mila
1282 For million(s) we use the plural, if more than one
1283 Also, one million is abbreviated in it, like on-million,
1284 or 'un milione', not 'uno milione'.
1285 So the right file is provided.
1288 while(!res && (num || playh)) {
1290 snprintf(fn, sizeof(fn), "digits/minus");
1291 if ( num > INT_MIN ) {
1297 snprintf(fn, sizeof(fn), "digits/hundred");
1299 } else if (num < 20) {
1300 snprintf(fn, sizeof(fn), "digits/%d", num);
1302 } else if (num == 21) {
1303 snprintf(fn, sizeof(fn), "digits/%d", num);
1305 } else if (num == 28) {
1306 snprintf(fn, sizeof(fn), "digits/%d", num);
1308 } else if (num == 31) {
1309 snprintf(fn, sizeof(fn), "digits/%d", num);
1311 } else if (num == 38) {
1312 snprintf(fn, sizeof(fn), "digits/%d", num);
1314 } else if (num == 41) {
1315 snprintf(fn, sizeof(fn), "digits/%d", num);
1317 } else if (num == 48) {
1318 snprintf(fn, sizeof(fn), "digits/%d", num);
1320 } else if (num == 51) {
1321 snprintf(fn, sizeof(fn), "digits/%d", num);
1323 } else if (num == 58) {
1324 snprintf(fn, sizeof(fn), "digits/%d", num);
1326 } else if (num == 61) {
1327 snprintf(fn, sizeof(fn), "digits/%d", num);
1329 } else if (num == 68) {
1330 snprintf(fn, sizeof(fn), "digits/%d", num);
1332 } else if (num == 71) {
1333 snprintf(fn, sizeof(fn), "digits/%d", num);
1335 } else if (num == 78) {
1336 snprintf(fn, sizeof(fn), "digits/%d", num);
1338 } else if (num == 81) {
1339 snprintf(fn, sizeof(fn), "digits/%d", num);
1341 } else if (num == 88) {
1342 snprintf(fn, sizeof(fn), "digits/%d", num);
1344 } else if (num == 91) {
1345 snprintf(fn, sizeof(fn), "digits/%d", num);
1347 } else if (num == 98) {
1348 snprintf(fn, sizeof(fn), "digits/%d", num);
1350 } else if (num < 100) {
1351 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1352 num -= ((num / 10) * 10);
1355 if ((num / 100) > 1) {
1356 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1359 snprintf(fn, sizeof(fn), "digits/hundred");
1361 num -= ((num / 100) * 100);
1363 if (num < 1000000) { /* 1,000,000 */
1365 res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1370 if ((tempnum / 1000) < 2)
1371 snprintf(fn, sizeof(fn), "digits/thousand");
1372 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1373 snprintf(fn, sizeof(fn), "digits/thousands");
1375 if (num < 1000000000) { /* 1,000,000,000 */
1376 if ((num / 1000000) > 1)
1377 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1381 num = num % 1000000;
1382 if ((tempnum / 1000000) < 2)
1383 snprintf(fn, sizeof(fn), "digits/million");
1385 snprintf(fn, sizeof(fn), "digits/millions");
1387 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1394 if(!ast_streamfile(chan, fn, language)) {
1395 if (audiofd && ctrlfd)
1396 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1398 res = ast_waitstream(chan, ints);
1400 ast_stopstream(chan);
1406 /*--- ast_say_number_full_nl: dutch syntax */
1407 /* New files: digits/nl-en
1409 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1416 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1417 while (!res && (num || playh )) {
1419 snprintf(fn, sizeof(fn), "digits/minus");
1420 if ( num > INT_MIN ) {
1426 snprintf(fn, sizeof(fn), "digits/hundred");
1428 } else if (num < 20) {
1429 snprintf(fn, sizeof(fn), "digits/%d", num);
1431 } else if (num < 100) {
1434 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1438 snprintf(fn, sizeof(fn), "digits/nl-en");
1440 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1445 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1447 num -= ((num / 100) * 100);
1449 if (num < 1000000) { /* 1,000,000 */
1450 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
1454 snprintf(fn, sizeof(fn), "digits/thousand");
1456 if (num < 1000000000) { /* 1,000,000,000 */
1457 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1460 num = num % 1000000;
1461 snprintf(fn, sizeof(fn), "digits/million");
1463 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1471 if(!ast_streamfile(chan, fn, language)) {
1472 if (audiofd && ctrlfd)
1473 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1475 res = ast_waitstream(chan, ints);
1477 ast_stopstream(chan);
1483 /*--- ast_say_number_full_no: Norwegian syntax */
1485 In addition to American English, the following sounds are required: "and", "1N"
1487 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)
1492 int cn = 1; /* +1 = commune; -1 = neuter */
1496 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1498 if (options && !strncasecmp(options, "n",1)) cn = -1;
1500 while(!res && (num || playh || playa )) {
1501 /* The grammar for Norwegian numbers is the same as for English except
1502 * for the following:
1503 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1504 * "and" before the last two digits, i.e. 2034 is "two thousand and
1505 * thirty-four" and 1000012 is "one million and twelve".
1508 snprintf(fn, sizeof(fn), "digits/minus");
1509 if ( num > INT_MIN ) {
1515 snprintf(fn, sizeof(fn), "digits/hundred");
1518 snprintf(fn, sizeof(fn), "digits/and");
1520 } else if (num == 1 && cn == -1) {
1521 snprintf(fn, sizeof(fn), "digits/1N");
1523 } else if (num < 20) {
1524 snprintf(fn, sizeof(fn), "digits/%d", num);
1526 } else if (num < 100) {
1527 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1528 num -= ((num / 10) * 10);
1529 } else if (num < 1000) {
1530 int hundreds = num / 100;
1532 snprintf(fn, sizeof(fn), "digits/1N");
1534 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1537 num -= 100 * hundreds;
1540 } else if (num < 1000000) {
1541 res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1544 snprintf(fn, sizeof(fn), "digits/thousand");
1546 if (num && num < 100)
1548 } else if (num < 1000000000) {
1549 int millions = num / 1000000;
1550 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1553 snprintf(fn, sizeof(fn), "digits/million");
1554 num = num % 1000000;
1555 if (num && num < 100)
1558 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1563 if(!ast_streamfile(chan, fn, language)) {
1564 if (audiofd && ctrlfd)
1565 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1567 res = ast_waitstream(chan, ints);
1569 ast_stopstream(chan);
1576 char *separator_dziesiatek;
1580 char *dziesiatki[10];
1585 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1591 return odm->rzedy[rzad - 1][0];
1592 if ((i > 21 || i < 11) && i%10 > 1 && i%10 < 5)
1593 return odm->rzedy[rzad - 1][1];
1595 return odm->rzedy[rzad - 1][2];
1598 static char* pl_append(char* buffer, char* str)
1600 strcpy(buffer, str);
1601 buffer += strlen(str);
1605 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1607 char file_name[255] = "digits/";
1608 strcat(file_name, fn);
1609 ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
1610 if (!ast_streamfile(chan, file_name, language)) {
1611 if (audiofd && ctrlfd)
1612 ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1614 ast_waitstream(chan, ints);
1616 ast_stopstream(chan);
1619 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1621 /* Initialise variables to allow compilation on Debian-stable, etc */
1631 if (i == 0 && rzad > 0) {
1635 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1638 m1000E6 = i % 1000000000;
1639 i1000E6 = i / 1000000000;
1641 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1643 m1000E3 = m1000E6 % 1000000;
1644 i1000E3 = m1000E6 / 1000000;
1646 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1648 m1000 = m1000E3 % 1000;
1649 i1000 = m1000E3 / 1000;
1651 powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1657 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1659 if ( m100 > 0 && m100 <=9 ) {
1661 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1663 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1664 } else if (m100 % 10 == 0) {
1665 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1666 } else if (m100 <= 19 ) {
1667 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1668 } else if (m100 != 0) {
1669 if (odm->separator_dziesiatek[0]==' ') {
1670 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1671 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1675 b = pl_append(b, odm->dziesiatki[m100 / 10]);
1676 b = pl_append(b, odm->separator_dziesiatek);
1677 b = pl_append(b, odm->cyfry2[m100 % 10]);
1678 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1683 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1687 /* ast_say_number_full_pl: Polish syntax */
1688 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)
1698 1000000000.2 miliardy
1699 1000000000.5 miliardow
1763 70m siedemdziesieciu
1775 90m dziewiedziesieciu
1777 and combinations of eg.: 20_1, 30m_3m, etc...
1781 char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1783 char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1785 char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m", /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1787 char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1789 char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1791 char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1793 char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1795 char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1797 char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1799 char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1801 char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1803 char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1805 char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}};
1807 /* Initialise variables to allow compilation on Debian-stable, etc */
1810 static odmiana *odmiana_nieosobowa = NULL;
1811 static odmiana *odmiana_meska = NULL;
1812 static odmiana *odmiana_zenska = NULL;
1814 if (odmiana_nieosobowa == NULL) {
1815 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
1817 odmiana_nieosobowa->separator_dziesiatek = "_";
1819 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1820 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1821 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1822 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1823 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1824 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1827 if (odmiana_zenska == NULL) {
1828 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
1830 odmiana_zenska->separator_dziesiatek = " ";
1832 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
1833 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
1834 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
1835 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
1836 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
1837 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
1840 if (odmiana_meska == NULL) {
1841 odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
1843 odmiana_meska->separator_dziesiatek = " ";
1845 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
1846 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
1847 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
1848 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
1849 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
1850 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
1854 if (strncasecmp(options, "f", 1) == 0)
1856 else if (strncasecmp(options, "m", 1) == 0)
1859 o = odmiana_nieosobowa;
1861 o = odmiana_nieosobowa;
1863 powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
1867 /* ast_say_number_full_pt: Portuguese syntax */
1868 /* Extra sounds needed: */
1869 /* For feminin all sound files end with F */
1870 /* 100E for 100+ something */
1871 /* 1000000S for plural */
1872 /* pt-e for 'and' */
1873 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)
1877 int mf = 1; /* +1 = male; -1 = female */
1881 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1883 if (options && !strncasecmp(options, "f",1))
1886 while(!res && num ) {
1888 snprintf(fn, sizeof(fn), "digits/minus");
1889 if ( num > INT_MIN ) {
1894 } else if (num < 20) {
1895 if ((num == 1 || num == 2) && (mf < 0))
1896 snprintf(fn, sizeof(fn), "digits/%dF", num);
1898 snprintf(fn, sizeof(fn), "digits/%d", num);
1900 } else if (num < 100) {
1901 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
1905 } else if (num < 1000) {
1907 snprintf(fn, sizeof(fn), "digits/100");
1909 snprintf(fn, sizeof(fn), "digits/100E");
1911 if (mf < 0 && num > 199)
1912 snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
1914 snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
1919 } else if (num < 1000000) {
1921 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
1925 snprintf(fn, sizeof(fn), "digits/1000");
1926 if ((num % 1000) && ((num % 1000) < 100 || !(num % 100)))
1929 } else if (num < 1000000000) {
1930 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
1934 snprintf(fn, sizeof(fn), "digits/1000000");
1936 snprintf(fn, sizeof(fn), "digits/1000000S");
1938 if ((num % 1000000) &&
1940 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
1941 /* no hundreds and below */
1942 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
1944 num = num % 1000000;
1946 if (!res && playh) {
1947 res = wait_file(chan, ints, "digits/pt-e", language);
1948 ast_stopstream(chan);
1952 if (!ast_streamfile(chan, fn, language)) {
1953 if (audiofd && ctrlfd)
1954 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1956 res = ast_waitstream(chan, ints);
1958 ast_stopstream(chan);
1964 /*--- ast_say_number_full_se: Swedish syntax */
1965 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)
1970 int cn = 1; /* +1 = commune; -1 = neuter */
1972 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1973 if (options && !strncasecmp(options, "n",1)) cn = -1;
1975 while(!res && (num || playh)) {
1977 snprintf(fn, sizeof(fn), "digits/minus");
1978 if ( num > INT_MIN ) {
1984 snprintf(fn, sizeof(fn), "digits/hundred");
1986 } else if (num < 20) {
1987 snprintf(fn, sizeof(fn), "digits/%d", num);
1989 } else if (num < 100) {
1990 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1991 num -= ((num / 10) * 10);
1992 } else if (num == 1 && cn == -1) { /* En eller ett? */
1993 snprintf(fn, sizeof(fn), "digits/1N");
1997 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1999 num -= ((num / 100) * 100);
2001 if (num < 1000000) { /* 1,000,000 */
2002 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2007 snprintf(fn, sizeof(fn), "digits/thousand");
2009 if (num < 1000000000) { /* 1,000,000,000 */
2010 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2014 num = num % 1000000;
2015 snprintf(fn, sizeof(fn), "digits/million");
2017 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2024 if(!ast_streamfile(chan, fn, language)) {
2025 if (audiofd && ctrlfd)
2026 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2028 res = ast_waitstream(chan, ints);
2029 ast_stopstream(chan);
2036 /*--- ast_say_number_full_tw: Taiwanese syntax */
2037 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2043 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2045 while(!res && (num || playh)) {
2047 snprintf(fn, sizeof(fn), "digits/minus");
2048 if ( num > INT_MIN ) {
2054 snprintf(fn, sizeof(fn), "digits/hundred");
2056 } else if (num < 10) {
2057 snprintf(fn, sizeof(fn), "digits/%d", num);
2059 } else if (num < 100) {
2060 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2061 num -= ((num / 10) * 10);
2064 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2066 num -= ((num / 100) * 100);
2068 if (num < 1000000) { /* 1,000,000 */
2069 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
2073 snprintf(fn, sizeof(fn), "digits/thousand");
2075 if (num < 1000000000) { /* 1,000,000,000 */
2076 res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2079 num = num % 1000000;
2080 snprintf(fn, sizeof(fn), "digits/million");
2082 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2089 if(!ast_streamfile(chan, fn, language)) {
2090 if (audiofd && ctrlfd)
2091 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2093 res = ast_waitstream(chan, ints);
2095 ast_stopstream(chan);
2101 /*--- ast_say_enumeration_full: call language-specific functions */
2102 /* Called from AGI */
2103 int ast_say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2105 if (!strcasecmp(language,"en") ) { /* English syntax */
2106 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2107 } else if (!strcasecmp(language, "de") ) { /* German syntax */
2108 return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2111 /* Default to english */
2112 return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2115 /*--- ast_say_enumeration: call language-specific functions without file descriptors */
2116 int ast_say_enumeration(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
2118 return(ast_say_enumeration_full(chan, num, ints, language, options, -1, -1));
2121 /*--- ast_say_enumeration_full_en: English syntax */
2122 /* This is the default syntax, if no other syntax defined in this file is used */
2123 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2128 while(!res && num) {
2130 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2131 if ( num > INT_MIN ) {
2136 } else if (num < 20) {
2137 snprintf(fn, sizeof(fn), "digits/h-%d", num);
2139 } else if (num < 100) {
2140 int tens = num / 10;
2143 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2145 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2147 } else if (num < 1000) {
2148 int hundreds = num / 100;
2150 if (hundreds > 1 || t == 1) {
2151 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2156 snprintf(fn, sizeof(fn), "digits/hundred");
2158 snprintf(fn, sizeof(fn), "digits/h-hundred");
2160 } else if (num < 1000000) {
2161 int thousands = num / 1000;
2163 if (thousands > 1 || t == 1) {
2164 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2169 snprintf(fn, sizeof(fn), "digits/thousand");
2171 snprintf(fn, sizeof(fn), "digits/h-thousand");
2174 } else if (num < 1000000000) {
2175 int millions = num / 1000000;
2176 num = num % 1000000;
2178 res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2182 snprintf(fn, sizeof(fn), "digits/million");
2184 snprintf(fn, sizeof(fn), "digits/h-million");
2186 } else if (num < INT_MAX) {
2187 int billions = num / 1000000000;
2188 num = num % 1000000000;
2190 res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2194 snprintf(fn, sizeof(fn), "digits/billion");
2196 snprintf(fn, sizeof(fn), "digits/h-billion");
2198 } else if (num == INT_MAX) {
2199 snprintf(fn, sizeof(fn), "digits/h-last");
2202 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2207 if (!ast_streamfile(chan, fn, language)) {
2208 if (audiofd && ctrlfd) {
2209 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2211 res = ast_waitstream(chan, ints);
2214 ast_stopstream(chan);
2220 /*--- ast_say_enumeration_full_de: German syntax */
2221 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)
2223 /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2225 char fn[256] = "", fna[256] = "";
2228 if (options && !strncasecmp(options, "f",1)) {
2230 } else if (options && !strncasecmp(options, "n",1)) {
2237 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2239 while(!res && num) {
2241 snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2242 if ( num > INT_MIN ) {
2247 } else if (num < 100 && t) {
2248 snprintf(fn, sizeof(fn), "digits/and");
2250 } else if (num < 20) {
2251 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2253 } else if (num < 100) {
2254 int ones = num % 10;
2256 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2259 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2262 } else if (num == 100 && t == 0) {
2263 snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2265 } else if (num < 1000) {
2266 int hundreds = num / 100;
2268 if (hundreds == 1) {
2269 snprintf(fn, sizeof(fn), "digits/1N");
2271 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2274 snprintf(fna, sizeof(fna), "digits/hundred");
2276 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2279 } else if (num < 1000000) {
2280 int thousands = num / 1000;
2282 if (thousands == 1) {
2284 snprintf(fn, sizeof(fn), "digits/1N");
2285 snprintf(fna, sizeof(fna), "digits/thousand");
2288 snprintf(fn, sizeof(fn), "digits/1N");
2289 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2291 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2295 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2300 snprintf(fn, sizeof(fn), "digits/thousand");
2302 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2306 } else if (num < 1000000000) {
2307 int millions = num / 1000000;
2308 num = num % 1000000;
2309 if (millions == 1) {
2311 snprintf(fn, sizeof(fn), "digits/1F");
2312 snprintf(fna, sizeof(fna), "digits/million");
2314 snprintf(fn, sizeof(fn), "digits/1N");
2315 snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2318 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2323 snprintf(fn, sizeof(fn), "digits/millions");
2325 snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2329 } else if (num < INT_MAX) {
2330 int billions = num / 1000000000;
2331 num = num % 1000000000;
2332 if (billions == 1) {
2334 snprintf(fn, sizeof(fn), "digits/1F");
2335 snprintf(fna, sizeof(fna), "digits/milliard");
2337 snprintf(fn, sizeof(fn), "digits/1N");
2338 snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2341 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2345 snprintf(fn, sizeof(fna), "digits/milliards");
2347 snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2351 } else if (num == INT_MAX) {
2352 snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2355 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2360 if (!ast_streamfile(chan, fn, language)) {
2361 if (audiofd && ctrlfd)
2362 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2364 res = ast_waitstream(chan, ints);
2366 ast_stopstream(chan);
2368 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2369 if (audiofd && ctrlfd) {
2370 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2372 res = ast_waitstream(chan, ints);
2375 ast_stopstream(chan);
2383 int ast_say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2385 if (!strcasecmp(lang, "en") ) { /* English syntax */
2386 return(ast_say_date_en(chan, t, ints, lang));
2387 } else if (!strcasecmp(lang, "de") ) { /* German syntax */
2388 return(ast_say_date_de(chan, t, ints, lang));
2389 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */
2390 return(ast_say_date_fr(chan, t, ints, lang));
2391 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */
2392 return(ast_say_date_nl(chan, t, ints, lang));
2393 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */
2394 return(ast_say_date_pt(chan, t, ints, lang));
2397 /* Default to English */
2398 return(ast_say_date_en(chan, t, ints, lang));
2401 /* English syntax */
2402 int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2407 ast_localtime(&t,&tm,NULL);
2409 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2410 res = ast_streamfile(chan, fn, lang);
2412 res = ast_waitstream(chan, ints);
2415 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2416 res = ast_streamfile(chan, fn, lang);
2418 res = ast_waitstream(chan, ints);
2421 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2423 res = ast_waitstream(chan, ints);
2425 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2430 int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2435 ast_localtime(&t,&tm,NULL);
2437 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2438 res = ast_streamfile(chan, fn, lang);
2440 res = ast_waitstream(chan, ints);
2443 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2445 res = ast_waitstream(chan, ints);
2447 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2448 res = ast_streamfile(chan, fn, lang);
2450 res = ast_waitstream(chan, ints);
2454 int year = tm.tm_year + 1900;
2455 if (year > 1999) { /* year 2000 and later */
2456 res = ast_say_number(chan, year, ints, lang, (char *) NULL);
2459 /* I'm not going to handle 1100 and prior */
2460 /* We'll just be silent on the year, instead of bombing out. */
2462 /* year 1100 to 1999. will anybody need this?!? */
2463 /* say 1967 as 'neunzen hundert sieben und sechzig' */
2464 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) );
2465 res = wait_file(chan, ints, fn, lang);
2467 res = wait_file(chan,ints, "digits/hundred", lang);
2468 if (!res && year % 100 != 0) {
2469 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);
2479 int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2484 ast_localtime(&t,&tm,NULL);
2486 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2487 res = ast_streamfile(chan, fn, lang);
2489 res = ast_waitstream(chan, ints);
2492 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2494 res = ast_waitstream(chan, ints);
2496 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2497 res = ast_streamfile(chan, fn, lang);
2499 res = ast_waitstream(chan, ints);
2502 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2507 int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2512 ast_localtime(&t,&tm,NULL);
2514 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2515 res = ast_streamfile(chan, fn, lang);
2517 res = ast_waitstream(chan, ints);
2520 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2522 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2523 res = ast_streamfile(chan, fn, lang);
2525 res = ast_waitstream(chan, ints);
2528 res = ast_waitstream(chan, ints);
2530 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2534 /* Portuguese syntax */
2535 int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2540 ast_localtime(&t,&tm,NULL);
2541 localtime_r(&t,&tm);
2542 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2544 res = wait_file(chan, ints, fn, lang);
2546 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
2548 res = wait_file(chan, ints, "digits/pt-de", lang);
2549 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2551 res = wait_file(chan, ints, fn, lang);
2553 res = wait_file(chan, ints, "digits/pt-de", lang);
2555 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2560 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)
2562 if (!strcasecmp(lang, "en") ) { /* English syntax */
2563 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2564 } else if (!strcasecmp(lang, "de") ) { /* German syntax */
2565 return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone));
2566 } else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) { /* Spanish syntax */
2567 return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone));
2568 } else if (!strcasecmp(lang, "fr") ) { /* French syntax */
2569 return(ast_say_date_with_format_fr(chan, time, ints, lang, format, timezone));
2570 } else if (!strcasecmp(lang, "it") ) { /* Italian syntax */
2571 return(ast_say_date_with_format_it(chan, time, ints, lang, format, timezone));
2572 } else if (!strcasecmp(lang, "nl") ) { /* Dutch syntax */
2573 return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone));
2574 } else if (!strcasecmp(lang, "pt") ) { /* Portuguese syntax */
2575 return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone));
2576 } else if (!strcasecmp(lang, "tw") ) { /* Taiwanese syntax */
2577 return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone));
2580 /* Default to English */
2581 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2584 /* English syntax */
2585 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)
2588 int res=0, offset, sndoffset;
2589 char sndfile[256], nextmsg[256];
2591 ast_localtime(&time,&tm,timezone);
2593 for (offset=0 ; format[offset] != '\0' ; offset++) {
2594 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
2595 switch (format[offset]) {
2596 /* NOTE: if you add more options here, please try to be consistent with strftime(3) */
2598 /* Literal name of a sound file */
2600 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
2601 sndfile[sndoffset] = format[offset];
2602 sndfile[sndoffset] = '\0';
2603 res = wait_file(chan,ints,sndfile,lang);
2607 /* Sunday - Saturday */
2608 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
2609 res = wait_file(chan,ints,nextmsg,lang);
2614 /* January - December */
2615 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
2616 res = wait_file(chan,ints,nextmsg,lang);
2619 /* Month enumerated */
2620 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, (char *) NULL);
2624 /* First - Thirtyfirst */
2625 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char *) NULL);
2629 if (tm.tm_year > 99) {
2630 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2632 if (tm.tm_year < 1) {
2633 /* I'm not going to handle 1900 and prior */
2634 /* We'll just be silent on the year, instead of bombing out. */
2636 res = wait_file(chan,ints, "digits/19",lang);
2638 if (tm.tm_year <= 9) {
2640 res = wait_file(chan,ints, "digits/oh",lang);
2642 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2643 res = wait_file(chan,ints,nextmsg,lang);
2645 } else if (tm.tm_year <= 20) {
2647 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2648 res = wait_file(chan,ints,nextmsg,lang);
2652 ten = tm.tm_year / 10;
2653 one = tm.tm_year % 10;
2654 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
2655 res = wait_file(chan,ints,nextmsg,lang);
2658 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2659 res = wait_file(chan,ints,nextmsg,lang);
2670 if (tm.tm_hour == 0)
2671 snprintf(nextmsg,sizeof(nextmsg), "digits/12");
2672 else if (tm.tm_hour > 12)
2673 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
2675 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
2676 res = wait_file(chan,ints,nextmsg,lang);
2681 if (format[offset] == 'H') {
2683 if (tm.tm_hour < 10) {
2684 res = wait_file(chan,ints, "digits/oh",lang);
2688 if (tm.tm_hour == 0) {
2689 res = wait_file(chan,ints, "digits/oh",lang);
2693 if (tm.tm_hour != 0) {
2694 int remainder = tm.tm_hour;
2695 if (tm.tm_hour > 20) {
2696 res = wait_file(chan,ints, "digits/20",lang);
2700 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
2701 res = wait_file(chan,ints,nextmsg,lang);
2708 if (tm.tm_min == 0) {
2709 res = wait_file(chan,ints, "digits/oclock",lang);
2710 } else if (tm.tm_min < 10) {
2711 res = wait_file(chan,ints, "digits/oh",lang);
2713 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2714 res = wait_file(chan,ints,nextmsg,lang);
2716 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
2717 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2718 res = wait_file(chan,ints,nextmsg,lang);
2721 ten = (tm.tm_min / 10) * 10;
2722 one = (tm.tm_min % 10);
2723 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2724 res = wait_file(chan,ints,nextmsg,lang);
2726 /* Fifty, not fifty-zero */
2728 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2729 res = wait_file(chan,ints,nextmsg,lang);
2737 if (tm.tm_hour > 11)
2738 snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
2740 snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
2741 res = wait_file(chan,ints,nextmsg,lang);
2744 /* Shorthand for "Today", "Yesterday", or ABdY */
2750 gettimeofday(&now,NULL);
2751 ast_localtime(&now.tv_sec,&tmnow,timezone);
2752 /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
2753 /* In any case, it saves not having to do ast_mktime() */
2754 beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
2755 if (beg_today < time) {