Fix chan_phone error code (bug #3692)
[asterisk/asterisk.git] / say.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Say numbers and dates (maybe words one day too)
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  *
13  * 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr)
14  *                                              George Konstantoulakis <gkon@inaccessnetworks.com>
15  */
16
17 #include <sys/types.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <netinet/in.h>
21 #include <time.h>
22 #include <ctype.h>
23 #include <math.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>
31 #include "asterisk.h"
32 #include <stdio.h>
33
34 #ifdef SOLARIS
35 #include <iso/limits_iso.h>
36 #endif
37
38
39 /* Forward declaration */
40 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang);
41
42 int ast_say_digit_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
43 {
44         /* XXX Merge with full version? XXX */
45         char fn[256] = "";
46         int num = 0;
47         int res = 0;
48         while(fn2[num] && !res) {
49                 fn[0] = '\0';
50                 switch (fn2[num]) {
51                         case ('*'):
52                                 snprintf(fn, sizeof(fn), "digits/star");
53                                 break;
54                         case ('#'):
55                                 snprintf(fn, sizeof(fn), "digits/pound");
56                                 break;
57                         default:
58                                 if((fn2[num] >= '0') && (fn2[num] <= '9')){ /* Must be in {0-9} */
59                                         snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
60                                 }
61                 }
62                 if(!ast_strlen_zero(fn)){ /* if length == 0, then skip this digit as it is invalid */
63                         res = ast_streamfile(chan, fn, lang);
64                         if (!res)
65                                 res = ast_waitstream(chan, ints);
66                         ast_stopstream(chan);
67                 }
68                 num++;
69         }
70         return res;
71 }
72
73 int ast_say_character_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
74 {
75         /* XXX Merge with full version? XXX */
76         char fn[256] = "";
77         char ltr;
78         int num = 0;
79         int res = 0;
80         while(fn2[num] && !res) {
81                 fn[0] = '\0';
82                 switch (fn2[num]) {
83                         case ('*'):
84                                 snprintf(fn, sizeof(fn), "digits/star");
85                                 break;
86                         case ('#'):
87                                 snprintf(fn, sizeof(fn), "digits/pound");
88                                 break;
89                         case ('0'):
90                         case ('1'):
91                         case ('2'):
92                         case ('3'):
93                         case ('4'):
94                         case ('5'):
95                         case ('6'):
96                         case ('7'):
97                         case ('8'):
98                         case ('9'):
99                                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
100                                 break;
101                         case ('!'):
102                                 strncpy(fn, "letters/exclaimation-point", sizeof(fn));
103                                 break;          
104                         case ('@'):
105                                 strncpy(fn, "letters/at", sizeof(fn));
106                                 break;
107                         case ('$'):
108                                 strncpy(fn, "letters/dollar", sizeof(fn));
109                                 break;
110                         case ('-'):
111                                 strncpy(fn, "letters/dash", sizeof(fn));
112                                 break;
113                         case ('.'):
114                                 strncpy(fn, "letters/dot", sizeof(fn));
115                                 break;
116                         case ('='):
117                                 strncpy(fn, "letters/equals", sizeof(fn));
118                                 break;
119                         case ('+'):
120                                 strncpy(fn, "letters/plus", sizeof(fn));
121                                 break;
122                         case ('/'):
123                                 strncpy(fn, "letters/slash", sizeof(fn));
124                                 break;
125                         case (' '):
126                                 strncpy(fn, "letters/space", sizeof(fn));
127                                 break;
128                         default:
129                                 ltr = fn2[num];
130                                 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';         /* file names are all lower-case */
131                                 snprintf(fn, sizeof(fn), "letters/%c", ltr);
132                 }
133                 if(!ast_strlen_zero(fn)) { /* if length == 0, then skip this digit as it is invalid */
134                         res = ast_streamfile(chan, fn, lang);
135                         if (!res) 
136                                 res = ast_waitstream(chan, ints);
137                 }       ast_stopstream(chan);
138                 num++;
139         }
140         return res;
141 }
142
143 int ast_say_phonetic_str(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang)
144 {
145         /* XXX Merge with full version? XXX */
146         char fn[256] = "";
147         char ltr;
148         int num = 0;
149         int res = 0;
150         int temp;
151         int play;
152         char hex[3];
153 /*      while(fn2[num] && !res) { */
154         while(fn2[num]) {
155                 play=1;
156                 switch (fn2[num]) {
157                         case ('*'):
158                                 snprintf(fn, sizeof(fn), "digits/star");
159                                 break;
160                         case ('#'):
161                                 snprintf(fn, sizeof(fn), "digits/pound");
162                                 break;
163                         case ('0'):
164                         case ('1'):
165                         case ('2'):
166                         case ('3'):
167                         case ('4'):
168                         case ('5'):
169                         case ('6'):
170                         case ('7'):
171                         case ('8'):
172                                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
173                                 break;
174                         case ('!'):
175                                 strncpy(fn, "exclaimation-point", sizeof(fn));
176                                 break;          
177                         case ('@'):
178                                 strncpy(fn, "at", sizeof(fn));
179                                 break;
180                         case ('$'):
181                                 strncpy(fn, "dollar", sizeof(fn));
182                                 break;  
183                         case ('-'):
184                                 strncpy(fn, "dash", sizeof(fn));
185                                 break;
186                         case ('.'):
187                                 strncpy(fn, "dot", sizeof(fn));
188                                 break;
189                         case ('='):
190                                 strncpy(fn, "equals", sizeof(fn));
191                                 break;
192                         case ('+'):
193                                 strncpy(fn, "plus", sizeof(fn));
194                                 break;
195                         case ('/'):
196                                 strncpy(fn, "slash", sizeof(fn));
197                                 break;
198                         case (' '):
199                                 strncpy(fn, "space", sizeof(fn));
200                                 break;
201                         case ('%'):
202                                 play=0;
203                                 /* check if we have 2 chars after the % */
204                                 if (strlen(fn2) > num+2)
205                                 {
206                                     hex[0]=fn2[num+1];
207                                     hex[1]=fn2[num+2];
208                                     hex[2]='\0';
209                                     if (sscanf(hex,"%x", &temp))
210                                     { /* Hex to char convertion successfull */
211                                         num++;
212                                         if (temp==37)
213                                         { /* If it is a percent, play it now */
214                                             strncpy(fn, "percent", sizeof(fn));
215                                                 num++;
216                                                 play=1;
217                                                 }
218                                                 /* check for invalid characters */
219                                                 if ((temp<32) || (temp>126))
220                                                 {
221                                                     num++;
222                                                 }
223                                     }
224                                 }
225                                 else
226                                     num++;
227                                 break;
228                         default:        /* '9' falls through to here, too */
229                                 ltr = tolower(fn2[num]);
230                                 snprintf(fn, sizeof(fn), "phonetic/%c_p", ltr);
231                 }
232                 if (play)
233                 {
234                     res = ast_streamfile(chan, fn, lang);
235                     if (!res) 
236                         res = ast_waitstream(chan, ints);
237                     ast_stopstream(chan);
238                 }
239                 num++;
240         }
241         return res;
242 }
243
244 int ast_say_digit_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
245 {
246         char fn[256] = "";
247         int num = 0;
248         int res = 0;
249         while(fn2[num] && !res) {
250                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
251                 res = ast_streamfile(chan, fn, lang);
252                 if (!res) 
253                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
254                 ast_stopstream(chan);
255                 num++;
256         }
257         return res;
258 }
259
260 int ast_say_character_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
261 {
262         char fn[256] = "";
263         char ltr;
264         int num = 0;
265         int res = 0;
266         while(fn2[num] && !res) {
267                 switch (fn2[num]) {
268                         case ('*'):
269                                 snprintf(fn, sizeof(fn), "digits/star");
270                                 break;
271                         case ('#'):
272                                 snprintf(fn, sizeof(fn), "digits/pound");
273                                 break;
274                         case ('0'):
275                         case ('1'):
276                         case ('2'):
277                         case ('3'):
278                         case ('4'):
279                         case ('5'):
280                         case ('6'):
281                         case ('7'):
282                         case ('8'):
283                         case ('9'):
284                                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
285                                 break;
286                         case ('!'):
287                                 strncpy(fn, "exclaimation-point", sizeof(fn));
288                                 break;          
289                         case ('@'):
290                                 strncpy(fn, "at", sizeof(fn));
291                                 break;
292                         case ('$'):
293                                 strncpy(fn, "dollar", sizeof(fn));
294                                 break;
295                         case ('-'):
296                                 strncpy(fn, "dash", sizeof(fn));
297                                 break;
298                         case ('.'):
299                                 strncpy(fn, "dot", sizeof(fn));
300                                 break;
301                         case ('='):
302                                 strncpy(fn, "equals", sizeof(fn));
303                                 break;
304                         case ('+'):
305                                 strncpy(fn, "plus", sizeof(fn));
306                                 break;
307                         case ('/'):
308                                 strncpy(fn, "slash", sizeof(fn));
309                                 break;
310                         case (' '):
311                                 strncpy(fn, "space", sizeof(fn));
312                                 break;
313                         default:
314                                 ltr = fn2[num];
315                                 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';         /* file names are all lower-case */
316                                 snprintf(fn, sizeof(fn), "letters/%c", ltr);
317                 }
318                 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
319                 res = ast_streamfile(chan, fn, lang);
320                 if (!res) 
321                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
322                 ast_stopstream(chan);
323                 num++;
324         }
325         return res;
326 }
327
328 int ast_say_phonetic_str_full(struct ast_channel *chan, const char *fn2, const char *ints, const char *lang, int audiofd, int ctrlfd)
329 {
330         char fn[256] = "";
331         char ltr;
332         int num = 0;
333         int res = 0;
334         while(fn2[num] && !res) {
335                 switch (fn2[num]) {
336                         case ('*'):
337                                 snprintf(fn, sizeof(fn), "digits/star");
338                                 break;
339                         case ('#'):
340                                 snprintf(fn, sizeof(fn), "digits/pound");
341                                 break;
342                         case ('0'):
343                         case ('1'):
344                         case ('2'):
345                         case ('3'):
346                         case ('4'):
347                         case ('5'):
348                         case ('6'):
349                         case ('7'):
350                         case ('8'):
351                                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
352                                 break;
353                         case ('!'):
354                                 strncpy(fn, "exclaimation-point", sizeof(fn));
355                                 break;          
356                         case ('@'):
357                                 strncpy(fn, "at", sizeof(fn));
358                                 break;
359                         case ('$'):
360                                 strncpy(fn, "dollar", sizeof(fn));
361                                 break;
362                         case ('-'):
363                                 strncpy(fn, "dash", sizeof(fn));
364                                 break;
365                         case ('.'):
366                                 strncpy(fn, "dot", sizeof(fn));
367                                 break;
368                         case ('='):
369                                 strncpy(fn, "equals", sizeof(fn));
370                                 break;
371                         case ('+'):
372                                 strncpy(fn, "plus", sizeof(fn));
373                                 break;
374                         case ('/'):
375                                 strncpy(fn, "slash", sizeof(fn));
376                                 break;
377                         case (' '):
378                                 strncpy(fn, "space", sizeof(fn));
379                                 break;
380                         default:        /* '9' falls here... */
381                                 ltr = fn2[num];
382                                 if ('A' <= ltr && ltr <= 'Z') ltr += 'a' - 'A';         /* file names are all lower-case */
383                                 snprintf(fn, sizeof(fn), "phonetic/%c", ltr);
384                         }
385                 /* snprintf(fn, sizeof(fn), "digits/%c", fn2[num]); */
386                 res = ast_streamfile(chan, fn, lang);
387                 if (!res) 
388                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
389                 ast_stopstream(chan);
390                 num++;
391         }
392         return res;
393 }
394
395 int ast_say_digits(struct ast_channel *chan, int num, const char *ints, const char *lang)
396 {
397         /* XXX Should I be merged with say_digits_full XXX */
398         char fn2[256];
399         snprintf(fn2, sizeof(fn2), "%d", num);
400         return ast_say_digit_str(chan, fn2, ints, lang);
401 }
402
403 int ast_say_digits_full(struct ast_channel *chan, int num, const char *ints, const char *lang, int audiofd, int ctrlfd)
404 {
405         char fn2[256];
406         snprintf(fn2, sizeof(fn2), "%d", num);
407         return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
408 }
409
410 /* Forward declarations */
411 /* Syntaxes supported, not really language codes.
412       da    - Danish
413       de    - German
414       en    - English (US)
415       en_GB - English (British)
416       es    - Spanish, Mexican
417       fr    - French
418       it    - Italian
419       nl    - Dutch
420       no    - Norwegian
421       pl    - Polish       
422       pt    - Portuguese
423       se    - Swedish
424       tw    - Taiwanese
425
426  Gender:
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
431  
432  Date/Time functions currently have less languages supported than saynumber().
433
434  Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
435
436  See contrib/i18n.testsuite.conf for some examples of the different syntaxes
437
438  Portuguese sound files needed for Time/Date functions:
439  pt-ah
440  pt-ao
441  pt-de
442  pt-e
443  pt-ora
444  pt-meianoite
445  pt-meiodia
446  pt-sss
447
448  Spanish sound files needed for Time/Date functions:
449  es-de
450  es-el
451
452  Italian sound files needed for Time/Date functions:
453  ore-una
454  ore-mezzanotte
455
456 */
457
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);
474
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_de(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd);
478
479 /* Forward declarations of ast_say_date, ast_say_datetime and ast_say_time functions */
480 static int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
481 static int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
482 static int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
483 static int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
484 static int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
485 static int ast_say_date_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
486
487 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);
488 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);
489 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);
490 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);
491 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);
492 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);
493 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);
494 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);
495 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);
496
497 static int ast_say_time_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
498 static int ast_say_time_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
499 static int ast_say_time_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
500 static int ast_say_time_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
501 static int ast_say_time_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
502 static int ast_say_time_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
503 static int ast_say_time_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
504
505 static int ast_say_datetime_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
506 static int ast_say_datetime_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
507 static int ast_say_datetime_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
508 static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
509 static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
510 static int ast_say_datetime_tw(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
511 static int ast_say_datetime_gr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
512
513 static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
514 static int ast_say_datetime_from_now_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
515 static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang);
516
517 static int wait_file(struct ast_channel *chan, const char *ints, const char *file, const char *lang) 
518 {
519         int res;
520         if ((res = ast_streamfile(chan, file, lang)))
521                 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
522         if (!res)
523                 res = ast_waitstream(chan, ints);
524         return res;
525 }
526
527 /*--- ast_say_number_full: call language-specific functions */
528 /* Called from AGI */
529 int ast_say_number_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
530 {
531         if (!strcasecmp(language,"en") ) {      /* English syntax */
532            return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
533         } else if (!strcasecmp(language, "cz") ) {      /* Czech syntax */
534            return(ast_say_number_full_cz(chan, num, ints, language, options, audiofd, ctrlfd));
535         } else if (!strcasecmp(language, "da") ) {      /* Danish syntax */
536            return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
537         } else if (!strcasecmp(language, "de") ) {      /* German syntax */
538            return(ast_say_number_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
539         } else if (!strcasecmp(language, "en_GB") ) {   /* British syntax */
540            return(ast_say_number_full_en_GB(chan, num, ints, language, audiofd, ctrlfd));
541         } else if (!strcasecmp(language, "no") ) {      /* Norwegian syntax */
542            return(ast_say_number_full_no(chan, num, ints, language, options, audiofd, ctrlfd));
543         } else if (!strcasecmp(language, "es") || !strcasecmp(language, "mx")) {        /* Spanish syntax */
544            return(ast_say_number_full_es(chan, num, ints, language, options, audiofd, ctrlfd));
545         } else if (!strcasecmp(language, "fr") ) {      /* French syntax */
546            return(ast_say_number_full_fr(chan, num, ints, language, options, audiofd, ctrlfd));
547         } else if (!strcasecmp(language, "it") ) {      /* Italian syntax */
548            return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd));
549         } else if (!strcasecmp(language, "nl") ) {      /* Dutch syntax */
550            return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd));
551         } else if (!strcasecmp(language, "pl") ) {      /* Polish syntax */
552            return(ast_say_number_full_pl(chan, num, ints, language, options, audiofd, ctrlfd));
553         } else if (!strcasecmp(language, "pt") ) {      /* Portuguese syntax */
554            return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd));
555         } else if (!strcasecmp(language, "se") ) {      /* Swedish syntax */
556            return(ast_say_number_full_se(chan, num, ints, language, options, audiofd, ctrlfd));
557         } else if (!strcasecmp(language, "tw")) {       /* Taiwanese syntax */
558            return(ast_say_number_full_tw(chan, num, ints, language, audiofd, ctrlfd));
559         } else if (!strcasecmp(language, "gr") ) {      /* Greek syntax */
560                 return(ast_say_number_full_gr(chan, num, ints, language, audiofd, ctrlfd));
561         }
562
563         /* Default to english */
564         return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
565 }
566
567 /*--- ast_say_number: call language-specific functions without file descriptors */
568 int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
569 {
570         return(ast_say_number_full(chan, num, ints, language, options, -1, -1));
571 }
572
573 /*--- ast_say_number_full_en: English syntax */
574 /* This is the default syntax, if no other syntax defined in this file is used */
575 static int ast_say_number_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
576 {
577         int res = 0;
578         int playh = 0;
579         char fn[256] = "";
580         if (!num) 
581                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
582
583         while(!res && (num || playh)) {
584                 if (num < 0) {
585                         snprintf(fn, sizeof(fn), "digits/minus");
586                         if ( num > INT_MIN ) {
587                                 num = -num;
588                         } else {
589                                 num = 0;
590                         }       
591                 } else if (playh) {
592                         snprintf(fn, sizeof(fn), "digits/hundred");
593                         playh = 0;
594                 } else  if (num < 20) {
595                         snprintf(fn, sizeof(fn), "digits/%d", num);
596                         num = 0;
597                 } else  if (num < 100) {
598                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
599                         num -= ((num / 10) * 10);
600                 } else {
601                         if (num < 1000){
602                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
603                                 playh++;
604                                 num -= ((num / 100) * 100);
605                         } else {
606                                 if (num < 1000000) { /* 1,000,000 */
607                                         res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
608                                         if (res)
609                                                 return res;
610                                         num = num % 1000;
611                                         snprintf(fn, sizeof(fn), "digits/thousand");
612                                 } else {
613                                         if (num < 1000000000) { /* 1,000,000,000 */
614                                                 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
615                                                 if (res)
616                                                         return res;
617                                                 num = num % 1000000;
618                                                 snprintf(fn, sizeof(fn), "digits/million");
619                                         } else {
620                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
621                                                 res = -1;
622                                         }
623                                 }
624                         }
625                 }
626                 if (!res) {
627                         if(!ast_streamfile(chan, fn, language)) {
628                                 if ((audiofd  > -1) && (ctrlfd > -1))
629                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
630                                 else
631                                         res = ast_waitstream(chan, ints);
632                         }
633                         ast_stopstream(chan);
634                 }
635         }
636         return res;
637 }
638
639 static int exp10_int(int power)
640 {
641         int x, res= 1;
642         for (x=0;x<power;x++)
643                 res *= 10;
644         return res;
645 }
646
647 /*--- ast_say_number_full_cz: Czech syntax */
648 /* files needed:
649  * 1m,2m - gender male
650  * 1w,2w - gender female
651  * 3,4,...,20
652  * 30,40,...,90
653  * 
654  * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set 
655  * 
656  * for each number 10^(3n + 3) exist 3 files represented as:
657  *              1 tousand = jeden tisic = 1_E3
658  *              2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
659  *              5,6,... tousands = pet,sest,... tisic = 5_E3
660  *
661  *              million = _E6
662  *              miliard = _E9
663  *              etc...
664  *
665  * tousand, milion are  gender male, so 1 and 2 is 1m 2m
666  * miliard is gender female, so 1 and 2 is 1w 2w
667  */
668 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)
669 {
670         int res = 0;
671         int playh = 0;
672         char fn[256] = "";
673         
674         int hundered = 0;
675         int left = 0;
676         int length = 0;
677         
678         /* options - w = woman, m = man, n = neutral. Defaultl is woman */
679         if (!options)
680                 options = "w";
681         
682         if (!num) 
683                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
684         
685         while(!res && (num || playh)) {
686                 if (num < 0) {
687                         snprintf(fn, sizeof(fn), "digits/minus");
688                         if ( num > INT_MIN ) {
689                                 num = -num;
690                         } else {
691                                 num = 0;
692                         }       
693                 } else if (num < 3 ) {
694                         snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]);
695                         playh = 0;
696                         num = 0;
697                 } else if (num < 20) {
698                         snprintf(fn, sizeof(fn), "digits/%d",num);
699                         playh = 0;
700                         num = 0;
701                 } else if (num < 100) {
702                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
703                         num -= ((num / 10) * 10);
704                 } else if (num < 1000) {
705                         hundered = num / 100;
706                         if ( hundered == 1 ) {
707                                 snprintf(fn, sizeof(fn), "digits/1sto");
708                         } else if ( hundered == 2 ) {
709                                 snprintf(fn, sizeof(fn), "digits/2ste");
710                         } else {
711                                         res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd);
712                                 if (res)
713                                         return res;
714                                 if (hundered == 3 || hundered == 4) {   
715                                         snprintf(fn, sizeof(fn), "digits/sta");
716                                 } else if ( hundered > 4 ) {
717                                         snprintf(fn, sizeof(fn), "digits/set");
718                                 }
719                         }
720                         num -= (hundered * 100);
721                 } else { /* num > 1000 */
722                         length = (int)log10(num)+1;  
723                         while ( (length % 3 ) != 1 ) {
724                                 length--;               
725                         }
726                         left = num / (exp10_int(length-1));
727                         if ( left == 2 ) {  
728                                 switch (length-1) {
729                                         case 9: options = "w";  /* 1,000,000,000 gender female */
730                                                 break;
731                                         default : options = "m"; /* others are male */
732                                 }
733                         }
734                         if ( left > 1 ) { /* we dont say "one thousand" but only thousand */
735                                 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd);
736                                 if (res) 
737                                         return res;
738                         }
739                         if ( left >= 5 ) { /* >= 5 have the same declesion */
740                                 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1);      
741                         } else if ( left >= 2 && left <= 4 ) {
742                                 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1);
743                         } else { /* left == 1 */
744                                 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1);
745                         }
746                         num -= left * (exp10_int(length-1));
747                 }
748                 if (!res) {
749                         if(!ast_streamfile(chan, fn, language)) {
750                                 if ((audiofd > -1) && (ctrlfd > -1)) {
751                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
752                                 } else {
753                                         res = ast_waitstream(chan, ints);
754                                 }
755                         }
756                         ast_stopstream(chan);
757                 }
758         }
759         return res; 
760 }
761
762 /*--- ast_say_number_full_da: Danish syntax */
763 /* New files:
764  In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and" 
765  */
766 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)
767 {
768         int res = 0;
769         int playh = 0;
770         int playa = 0;
771         int cn = 1;             /* +1 = commune; -1 = neuter */
772         char fn[256] = "";
773         if (!num) 
774                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
775
776         if (options && !strncasecmp(options, "n",1)) cn = -1;
777
778         while(!res && (num || playh || playa )) {
779                 /* The grammar for Danish numbers is the same as for English except
780                 * for the following:
781                 * - 1 exists in both commune ("en", file "1N") and neuter ("et", file "1")
782                 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
783                 *   "one-and twenty" and 68 is "eight-and sixty".
784                 * - "million" is different in singular and plural form
785                 * - numbers > 1000 with zero as the third digit from last have an
786                 *   "and" before the last two digits, i.e. 2034 is "two thousand and
787                 *   four-and thirty" and 1000012 is "one million and twelve".
788                 */
789                 if (num < 0) {
790                         snprintf(fn, sizeof(fn), "digits/minus");
791                         if ( num > INT_MIN ) {
792                                 num = -num;
793                         } else {
794                                 num = 0;
795                         }       
796                 } else if (playh) {
797                         snprintf(fn, sizeof(fn), "digits/hundred");
798                         playh = 0;
799                 } else if (playa) {
800                         snprintf(fn, sizeof(fn), "digits/and");
801                         playa = 0;
802                 } else if (num == 1 && cn == -1) {
803                         snprintf(fn, sizeof(fn), "digits/1N");
804                         num = 0;
805                 } else if (num < 20) {
806                         snprintf(fn, sizeof(fn), "digits/%d", num);
807                         num = 0;
808                 } else if (num < 100) {
809                         int ones = num % 10;
810                         if (ones) {
811                                 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
812                                 num -= ones;
813                         } else {
814                                 snprintf(fn, sizeof(fn), "digits/%d", num);
815                                 num = 0;
816                         }
817                 } else {
818                         if (num < 1000) {
819                                 int hundreds = num / 100;
820                                 if (hundreds == 1)
821                                         snprintf(fn, sizeof(fn), "digits/1N");
822                                 else
823                                         snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
824
825                                 playh++;
826                                 num -= 100 * hundreds;
827                                 if (num)
828                                         playa++;
829
830                         } else {
831                                 if (num < 1000000) {
832                                         res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
833                                         if (res)
834                                                 return res;
835                                         num = num % 1000;
836                                         snprintf(fn, sizeof(fn), "digits/thousand");
837                                 } else {
838                                         if (num < 1000000000) {
839                                                 int millions = num / 1000000;
840                                                 res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
841                                                 if (res)
842                                                         return res;
843                                                 if (millions == 1)
844                                                         snprintf(fn, sizeof(fn), "digits/million");
845                                                 else
846                                                         snprintf(fn, sizeof(fn), "digits/millions");
847                                                 num = num % 1000000;
848                                         } else {
849                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
850                                                 res = -1;
851                                         }
852                                 }
853                                 if (num && num < 100)
854                                         playa++;
855                         }
856                 }
857                 if (!res) {
858                         if(!ast_streamfile(chan, fn, language)) {
859                                 if ((audiofd > -1) && (ctrlfd > -1)) 
860                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
861                                 else  
862                                         res = ast_waitstream(chan, ints);
863                         }
864                         ast_stopstream(chan);
865                 }
866         }
867         return res;
868 }
869
870 /*--- ast_say_number_full_de: German syntax */
871 /* New files:
872  In addition to English, the following sounds are required:
873  "millions"
874  "1-and" through "9-and" 
875  "1F" (eine)
876  "1N" (ein)
877  NB "1" is recorded as 'eins'
878  */
879 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)
880 {
881         int res = 0, t = 0;
882         int mf = 1;                            /* +1 = male and neuter; -1 = female */
883         char fn[256] = "";
884         char fna[256] = "";
885         if (!num) 
886                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
887
888         if (options && (!strncasecmp(options, "f",1)))
889                 mf = -1;
890
891         while(!res && num) {
892                 /* The grammar for German numbers is the same as for English except
893                 * for the following:
894                 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
895                 *   "one-and twenty" and 68 is "eight-and sixty".
896                 * - "one" varies according to gender
897                 * - 100 is 'hundert', however all other instances are 'ein hundert'
898                 * - 1000 is 'tausend', however all other instances are 'ein tausend'
899                 * - 1000000 is always 'eine million'
900                 * - "million" is different in singular and plural form
901                 */
902                 if (num < 0) {
903                         snprintf(fn, sizeof(fn), "digits/minus");
904                         if ( num > INT_MIN ) {
905                                 num = -num;
906                         } else {
907                                 num = 0;
908                         }       
909                 } else if (num < 100 && t) {
910                         snprintf(fn, sizeof(fn), "digits/and");
911                         t = 0;
912                 } else if (num == 1 && mf == -1) {
913                         snprintf(fn, sizeof(fn), "digits/%dF", num);
914                         num = 0;
915                 } else if (num < 20) {
916                         snprintf(fn, sizeof(fn), "digits/%d", num);
917                         num = 0;
918                 } else if (num < 100) {
919                         int ones = num % 10;
920                         if (ones) {
921                                 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
922                                 num -= ones;
923                         } else {
924                                 snprintf(fn, sizeof(fn), "digits/%d", num);
925                                 num = 0;
926                         }
927                 } else if (num == 100 && t == 0) {
928                         snprintf(fn, sizeof(fn), "digits/hundred");
929                         num = 0;
930                 } else if (num < 1000) {
931                         int hundreds = num / 100;
932                         num = num % 100;
933                         if (hundreds == 1) {
934                                 snprintf(fn, sizeof(fn), "digits/1N");
935                         } else {
936                                 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
937                         }
938                         snprintf(fna, sizeof(fna), "digits/hundred");
939                         t = 1;
940                 } else if (num == 1000 && t == 0) {
941                         snprintf(fn, sizeof(fn), "digits/thousand");
942                         num = 0;
943                 } else  if (num < 1000000) {
944                         int thousands = num / 1000;
945                         num = num % 1000;
946                         t = 1;
947                         if (thousands == 1) {
948                                 snprintf(fn, sizeof(fn), "digits/1N");
949                                 snprintf(fna, sizeof(fna), "digits/thousand");
950                         } else {
951                                 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
952                                 if (res)
953                                         return res;
954                                 snprintf(fn, sizeof(fn), "digits/thousand");
955                         }
956                 } else if (num < 1000000000) {
957                         int millions = num / 1000000;
958                         num = num % 1000000;
959                         t = 1;
960                         if (millions == 1) {
961                                 snprintf(fn, sizeof(fn), "digits/1F");
962                                 snprintf(fna, sizeof(fna), "digits/million");
963                         } else {
964                                 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
965                                 if (res)
966                                         return res;
967                                 snprintf(fn, sizeof(fn), "digits/millions");
968                         }
969                 } else if (num <= INT_MAX) {
970                         int billions = num / 1000000000;
971                         num = num % 1000000000;
972                         t = 1;
973                         if (billions == 1) {
974                                 snprintf(fn, sizeof(fn), "digits/1F");
975                                 snprintf(fna, sizeof(fna), "digits/milliard");
976                         } else {
977                                 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
978                                 if (res) {
979                                         return res;
980                                 }
981                                 snprintf(fn, sizeof(fn), "digits/milliards");
982                         }
983                 } else {
984                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
985                         res = -1;
986                 }
987                 if (!res) {
988                         if(!ast_streamfile(chan, fn, language)) {
989                                 if ((audiofd > -1) && (ctrlfd > -1)) 
990                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
991                                 else  
992                                         res = ast_waitstream(chan, ints);
993                         }
994                         ast_stopstream(chan);
995                         if (!res) {
996                                 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
997                                         if ((audiofd > -1) && (ctrlfd > -1))
998                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
999                                         else
1000                                                 res = ast_waitstream(chan, ints);
1001                                 }
1002                                 ast_stopstream(chan);
1003                                 strcpy(fna, "");
1004                         }
1005                 }
1006         }
1007         return res;
1008 }
1009
1010 /*--- ast_say_number_full_en_GB: British and Norwegian syntax */
1011 /* New files:
1012  In addition to American English, the following sounds are required:  "and"
1013  */
1014 static int ast_say_number_full_en_GB(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1015 {
1016         int res = 0;
1017         int playh = 0;
1018         int playa = 0;
1019         char fn[256] = "";
1020         if (!num) 
1021                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1022
1023         while(!res && (num || playh || playa )) {
1024                 if (num < 0) {
1025                         snprintf(fn, sizeof(fn), "digits/minus");
1026                         if ( num > INT_MIN ) {
1027                                 num = -num;
1028                         } else {
1029                                 num = 0;
1030                         }       
1031                 } else if (playh) {
1032                         snprintf(fn, sizeof(fn), "digits/hundred");
1033                         playh = 0;
1034                 } else if (playa) {
1035                         snprintf(fn, sizeof(fn), "digits/and");
1036                         playa = 0;
1037                 } else if (num < 20) {
1038                         snprintf(fn, sizeof(fn), "digits/%d", num);
1039                         num = 0;
1040                 } else if (num < 100) {
1041                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1042                         num -= ((num / 10) * 10);
1043                 } else if (num < 1000) {
1044                         int hundreds = num / 100;
1045                         snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1046
1047                         playh++;
1048                         num -= 100 * hundreds;
1049                         if (num)
1050                                 playa++;
1051                 } else  if (num < 1000000) {
1052                         res = ast_say_number_full_en_GB(chan, num / 1000, ints, language, audiofd, ctrlfd);
1053                         if (res)
1054                                 return res;
1055                         snprintf(fn, sizeof(fn), "digits/thousand");
1056                         num = num % 1000;
1057                         if (num && num < 100)
1058                                 playa++;
1059                 } else  if (num < 1000000000) {
1060                                 int millions = num / 1000000;
1061                                 res = ast_say_number_full_en_GB(chan, millions, ints, language, audiofd, ctrlfd);
1062                                 if (res)
1063                                         return res;
1064                                 snprintf(fn, sizeof(fn), "digits/million");
1065                                 num = num % 1000000;
1066                                 if (num && num < 100)
1067                                         playa++;
1068                 } else {
1069                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1070                                 res = -1;
1071                 }
1072                 
1073                 if (!res) {
1074                         if(!ast_streamfile(chan, fn, language)) {
1075                                 if ((audiofd > -1) && (ctrlfd > -1)) 
1076                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1077                                 else  
1078                                         res = ast_waitstream(chan, ints);
1079                         }
1080                         ast_stopstream(chan);
1081                 }
1082         }
1083         return res;
1084 }
1085
1086 /*--- ast_say_number_full_es: Spanish syntax */
1087 /* New files:
1088  Requires a few new audios:
1089    1F.gsm: feminine 'una'
1090    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 
1091  */
1092 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)
1093 {
1094         int res = 0;
1095         int playa = 0;
1096         int mf = 0;                            /* +1 = male; -1 = female */
1097         char fn[256] = "";
1098         if (!num) 
1099                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1100
1101         if (options) {
1102                 if (!strncasecmp(options, "f",1))
1103                         mf = -1;
1104                 else if (!strncasecmp(options, "m", 1))
1105                         mf = 1;
1106         }
1107
1108         while (!res && num) {
1109                 if (num < 0) {
1110                         snprintf(fn, sizeof(fn), "digits/minus");
1111                         if ( num > INT_MIN ) {
1112                                 num = -num;
1113                         } else {
1114                                 num = 0;
1115                         }       
1116                 } else if (playa) {
1117                         snprintf(fn, sizeof(fn), "digits/and");
1118                         playa = 0;
1119                 } else if (num == 1) {
1120                         if (mf < 0)
1121                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
1122                         else if (mf > 0)
1123                                 snprintf(fn, sizeof(fn), "digits/%dM", num);
1124                         else 
1125                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1126                         num = 0;
1127                 } else if (num < 31) {
1128                         snprintf(fn, sizeof(fn), "digits/%d", num);
1129                         num = 0;
1130                 } else if (num < 100) {
1131                         snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1132                         num -= ((num/10)*10);
1133                         if (num)
1134                                 playa++;
1135                 } else if (num == 100) {
1136                         snprintf(fn, sizeof(fn), "digits/100");
1137                         num = 0;
1138                 } else if (num < 200) {
1139                         snprintf(fn, sizeof(fn), "digits/100-and");
1140                         num -= 100;
1141                 } else {
1142                         if (num < 1000) {
1143                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
1144                                 num -= ((num/100)*100);
1145                         } else if (num < 2000) {
1146                                 num = num % 1000;
1147                                 snprintf(fn, sizeof(fn), "digits/thousand");
1148                         } else {
1149                                 if (num < 1000000) {
1150                                         res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1151                                         if (res)
1152                                                 return res;
1153                                         num = num % 1000;
1154                                         snprintf(fn, sizeof(fn), "digits/thousand");
1155                                 } else {
1156                                         if (num < 2147483640) {
1157                                                 if ((num/1000000) == 1) {
1158                                                         res = ast_say_number_full_es(chan, num / 1000000, ints, language, "M", audiofd, ctrlfd);
1159                                                         if (res)
1160                                                                 return res;
1161                                                         snprintf(fn, sizeof(fn), "digits/million");
1162                                                 } else {
1163                                                         res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1164                                                         if (res)
1165                                                                 return res;
1166                                                         snprintf(fn, sizeof(fn), "digits/millions");
1167                                                 }
1168                                                 num = num % 1000000;
1169                                         } else {
1170                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1171                                                 res = -1;
1172                                         }
1173                                 }
1174                         }
1175                 }
1176
1177                 if (!res) {
1178                         if(!ast_streamfile(chan, fn, language)) {
1179                                 if ((audiofd > -1) && (ctrlfd > -1))
1180                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1181                                 else
1182                                         res = ast_waitstream(chan, ints);
1183                         }
1184                         ast_stopstream(chan);
1185
1186                 }
1187                         
1188         }
1189         return res;
1190 }
1191
1192 /*--- ast_say_number_full_fr: French syntax */
1193 /*      Extra sounds needed:
1194         1F: feminin 'une'
1195         et: 'and' */
1196 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)
1197 {
1198         int res = 0;
1199         int playh = 0;
1200         int playa = 0;
1201         int mf = 1;                            /* +1 = male; -1 = female */
1202         char fn[256] = "";
1203         if (!num) 
1204                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1205         
1206         if (options && !strncasecmp(options, "f",1))
1207                 mf = -1;
1208
1209         while(!res && (num || playh || playa)) {
1210                 if (num < 0) {
1211                         snprintf(fn, sizeof(fn), "digits/minus");
1212                         if ( num > INT_MIN ) {
1213                                 num = -num;
1214                         } else {
1215                                 num = 0;
1216                         }       
1217                 } else if (playh) {
1218                         snprintf(fn, sizeof(fn), "digits/hundred");
1219                         playh = 0;
1220                 } else if (playa) {
1221                         snprintf(fn, sizeof(fn), "digits/et");
1222                         playa = 0;
1223                 } else if (num == 1) {
1224                         if (mf < 0)
1225                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
1226                         else
1227                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1228                         num = 0;
1229                 } else if (num < 21) {
1230                         snprintf(fn, sizeof(fn), "digits/%d", num);
1231                         num = 0;
1232                 } else if (num < 70) {
1233                         snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1234                         if ((num % 10) == 1) playa++;
1235                         num = num % 10;
1236                 } else if (num < 80) {
1237                         snprintf(fn, sizeof(fn), "digits/60");
1238                         if ((num % 10) == 1) playa++;
1239                         num = num - 60;
1240                 } else if (num < 100) {
1241                         snprintf(fn, sizeof(fn), "digits/80");
1242                         num = num - 80;
1243                 } else if (num < 200) {
1244                         snprintf(fn, sizeof(fn), "digits/hundred");
1245                         num = num - 100;
1246                 } else if (num < 1000) {
1247                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1248                         playh++;
1249                         num = num % 100;
1250                 } else if (num < 2000) {
1251                         snprintf(fn, sizeof(fn), "digits/thousand");
1252                         num = num - 1000;
1253                 } else if (num < 1000000) {
1254                         res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1255                         if (res)
1256                                 return res;
1257                         snprintf(fn, sizeof(fn), "digits/thousand");
1258                         num = num % 1000;
1259                 } else  if (num < 1000000000) {
1260                         res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1261                         if (res)
1262                                 return res;
1263                         snprintf(fn, sizeof(fn), "digits/million");
1264                         num = num % 1000000;
1265                 } else {
1266                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1267                         res = -1;
1268                 }
1269                 if (!res) {
1270                         if(!ast_streamfile(chan, fn, language)) {
1271                                 if ((audiofd > -1) && (ctrlfd > -1))
1272                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1273                                 else
1274                                         res = ast_waitstream(chan, ints);
1275                         }
1276                         ast_stopstream(chan);
1277                 }
1278         }
1279         return res;
1280 }
1281
1282 /*--- ast_say_number_full_it:  Italian */
1283 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1284 {
1285         int res = 0;
1286         int playh = 0;
1287         int tempnum = 0;
1288         char fn[256] = "";
1289
1290         if (!num)
1291                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1292
1293                 /*
1294                 Italian support
1295
1296                 Like english, numbers up to 20 are a single 'word', and others
1297                 compound, but with exceptions.
1298                 For example 21 is not twenty-one, but there is a single word in 'it'.
1299                 Idem for 28 (ie when a the 2nd part of a compund number
1300                 starts with a vowel)
1301
1302                 There are exceptions also for hundred, thousand and million.
1303                 In english 100 = one hundred, 200 is two hundred.
1304                 In italian 100 = cento , like to say hundred (without one),
1305                 200 and more are like english.
1306                 
1307                 Same applies for thousand:
1308                 1000 is one thousand in en, 2000 is two thousand.
1309                 In it we have 1000 = mille , 2000 = 2 mila 
1310
1311                 For million(s) we use the plural, if more than one
1312                 Also, one million is abbreviated in it, like on-million,
1313                 or 'un milione', not 'uno milione'.
1314                 So the right file is provided.
1315                 */
1316
1317                 while(!res && (num || playh)) {
1318                         if (num < 0) {
1319                                 snprintf(fn, sizeof(fn), "digits/minus");
1320                                 if ( num > INT_MIN ) {
1321                                         num = -num;
1322                                 } else {
1323                                         num = 0;
1324                                 }       
1325                         } else if (playh) {
1326                                 snprintf(fn, sizeof(fn), "digits/hundred");
1327                                 playh = 0;
1328                         } else if (num < 20) {
1329                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1330                                 num = 0;
1331                         } else if (num == 21) {
1332                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1333                                 num = 0;
1334                         } else if (num == 28) {
1335                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1336                                 num = 0;
1337                         } else if (num == 31) {
1338                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1339                                 num = 0;
1340                         } else if (num == 38) {
1341                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1342                                 num = 0;
1343                         } else if (num == 41) {
1344                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1345                                 num = 0;
1346                         } else if (num == 48) {
1347                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1348                                 num = 0;
1349                         } else if (num == 51) {
1350                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1351                                 num = 0;
1352                         } else if (num == 58) {
1353                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1354                                 num = 0;
1355                         } else if (num == 61) {
1356                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1357                                 num = 0;
1358                         } else if (num == 68) {
1359                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1360                                 num = 0;
1361                         } else if (num == 71) {
1362                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1363                                 num = 0;
1364                         } else if (num == 78) {
1365                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1366                                 num = 0;
1367                         } else if (num == 81) {
1368                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1369                                 num = 0;
1370                         } else if (num == 88) {
1371                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1372                                 num = 0;
1373                         } else if (num == 91) {
1374                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1375                                 num = 0;
1376                         } else if (num == 98) {
1377                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1378                                 num = 0;
1379                         } else if (num < 100) {
1380                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1381                                 num -= ((num / 10) * 10);
1382                         } else {
1383                                 if (num < 1000) {
1384                                         if ((num / 100) > 1) {
1385                                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1386                                                 playh++;
1387                                         } else {
1388                                                 snprintf(fn, sizeof(fn), "digits/hundred");
1389                                         }
1390                                         num -= ((num / 100) * 100);
1391                                 } else {
1392                                         if (num < 1000000) { /* 1,000,000 */
1393                                                 if ((num/1000) > 1)
1394                                                         res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1395                                                 if (res)
1396                                                         return res;
1397                                                 tempnum = num;
1398                                                 num = num % 1000;
1399                                                 if ((tempnum / 1000) < 2)
1400                                                         snprintf(fn, sizeof(fn), "digits/thousand");
1401                                                 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1402                                                         snprintf(fn, sizeof(fn), "digits/thousands");
1403                                         } else {
1404                                                 if (num < 1000000000) { /* 1,000,000,000 */
1405                                                         if ((num / 1000000) > 1)
1406                                                                 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1407                                                         if (res)
1408                                                                 return res;
1409                                                         tempnum = num;
1410                                                         num = num % 1000000;
1411                                                         if ((tempnum / 1000000) < 2)
1412                                                                 snprintf(fn, sizeof(fn), "digits/million");
1413                                                         else
1414                                                                 snprintf(fn, sizeof(fn), "digits/millions");
1415                                                 } else {
1416                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1417                                                         res = -1;
1418                                                 }
1419                                         }
1420                                 }
1421                         }
1422                         if (!res) {
1423                                 if(!ast_streamfile(chan, fn, language)) {
1424                                         if ((audiofd > -1) && (ctrlfd > -1))
1425                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1426                                         else
1427                                                 res = ast_waitstream(chan, ints);
1428                                 }
1429                                 ast_stopstream(chan);
1430                         }
1431                 }
1432         return res;
1433 }
1434
1435 /*--- ast_say_number_full_nl: dutch syntax */
1436 /* New files: digits/nl-en
1437  */
1438 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1439 {
1440         int res = 0;
1441         int playh = 0;
1442         int units = 0;
1443         char fn[256] = "";
1444         if (!num) 
1445                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1446         while (!res && (num || playh )) {
1447                 if (num < 0) {
1448                         snprintf(fn, sizeof(fn), "digits/minus");
1449                         if ( num > INT_MIN ) {
1450                                 num = -num;
1451                         } else {
1452                                 num = 0;
1453                         }       
1454                 } else if (playh) {
1455                         snprintf(fn, sizeof(fn), "digits/hundred");
1456                         playh = 0;
1457                 } else if (num < 20) {
1458                         snprintf(fn, sizeof(fn), "digits/%d", num);
1459                         num = 0;
1460                 } else if (num < 100) {
1461                         units = num % 10;
1462                         if (units > 0) {
1463                                 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1464                                 if (res)
1465                                         return res;
1466                                 num = num - units;
1467                                 snprintf(fn, sizeof(fn), "digits/nl-en");
1468                         } else {
1469                                 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1470                                 num = 0;
1471                         }
1472                 } else {
1473                         if (num < 1000) {
1474                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1475                                 playh++;
1476                                 num -= ((num / 100) * 100);
1477                         } else {
1478                                 if (num < 1000000) { /* 1,000,000 */
1479                                         res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
1480                                         if (res)
1481                                                 return res;
1482                                         num = num % 1000;
1483                                         snprintf(fn, sizeof(fn), "digits/thousand");
1484                                 } else {
1485                                         if (num < 1000000000) { /* 1,000,000,000 */
1486                                                 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1487                                                 if (res)
1488                                                         return res;
1489                                                 num = num % 1000000;
1490                                                 snprintf(fn, sizeof(fn), "digits/million");
1491                                         } else {
1492                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1493                                                 res = -1;
1494                                         }
1495                                 }
1496                         }
1497                 }
1498
1499                 if (!res) {
1500                         if(!ast_streamfile(chan, fn, language)) {
1501                                 if ((audiofd > -1) && (ctrlfd > -1))
1502                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1503                                 else
1504                                         res = ast_waitstream(chan, ints);
1505                         }
1506                         ast_stopstream(chan);
1507                 }
1508         }
1509         return res;
1510 }
1511
1512 /*--- ast_say_number_full_no: Norwegian syntax */
1513 /* New files:
1514  In addition to American English, the following sounds are required:  "and", "1N"
1515  */
1516 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)
1517 {
1518         int res = 0;
1519         int playh = 0;
1520         int playa = 0;
1521         int cn = 1;             /* +1 = commune; -1 = neuter */
1522         char fn[256] = "";
1523         
1524         if (!num) 
1525                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1526         
1527         if (options && !strncasecmp(options, "n",1)) cn = -1;
1528
1529         while(!res && (num || playh || playa )) {
1530                 /* The grammar for Norwegian numbers is the same as for English except
1531                 * for the following:
1532                 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1533                 *   "and" before the last two digits, i.e. 2034 is "two thousand and
1534                 *   thirty-four" and 1000012 is "one million and twelve".
1535                 */
1536                 if (num < 0) {
1537                         snprintf(fn, sizeof(fn), "digits/minus");
1538                         if ( num > INT_MIN ) {
1539                                 num = -num;
1540                         } else {
1541                                 num = 0;
1542                         }       
1543                 } else if (playh) {
1544                         snprintf(fn, sizeof(fn), "digits/hundred");
1545                         playh = 0;
1546                 } else if (playa) {
1547                         snprintf(fn, sizeof(fn), "digits/and");
1548                         playa = 0;
1549                 } else if (num == 1 && cn == -1) {
1550                         snprintf(fn, sizeof(fn), "digits/1N");
1551                         num = 0;
1552                 } else if (num < 20) {
1553                         snprintf(fn, sizeof(fn), "digits/%d", num);
1554                         num = 0;
1555                 } else if (num < 100) {
1556                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1557                         num -= ((num / 10) * 10);
1558                 } else if (num < 1000) {
1559                         int hundreds = num / 100;
1560                         if (hundreds == 1)
1561                                 snprintf(fn, sizeof(fn), "digits/1N");
1562                         else
1563                                 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1564
1565                         playh++;
1566                         num -= 100 * hundreds;
1567                         if (num)
1568                                 playa++;
1569                 } else  if (num < 1000000) {
1570                         res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1571                         if (res)
1572                                 return res;
1573                         snprintf(fn, sizeof(fn), "digits/thousand");
1574                         num = num % 1000;
1575                         if (num && num < 100)
1576                                 playa++;
1577                 } else  if (num < 1000000000) {
1578                                 int millions = num / 1000000;
1579                                 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1580                                 if (res)
1581                                         return res;
1582                                 snprintf(fn, sizeof(fn), "digits/million");
1583                                 num = num % 1000000;
1584                                 if (num && num < 100)
1585                                         playa++;
1586                 } else {
1587                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1588                                 res = -1;
1589                 }
1590                 
1591                 if (!res) {
1592                         if(!ast_streamfile(chan, fn, language)) {
1593                                 if ((audiofd > -1) && (ctrlfd > -1)) 
1594                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1595                                 else  
1596                                         res = ast_waitstream(chan, ints);
1597                         }
1598                         ast_stopstream(chan);
1599                 }
1600         }
1601         return res;
1602 }
1603
1604 typedef struct {  
1605         char *separator_dziesiatek;
1606         char *cyfry[10];
1607         char *cyfry2[10];
1608         char *setki[10];
1609         char *dziesiatki[10];
1610         char *nastki[10];  
1611         char *rzedy[3][3];
1612 } odmiana;
1613
1614 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1615 {
1616         if (rzad==0)
1617                 return "";
1618  
1619         if (i==1)
1620                 return odm->rzedy[rzad - 1][0];
1621         if ((i > 21 || i < 11) &&  i%10 > 1 && i%10 < 5)
1622                 return odm->rzedy[rzad - 1][1];
1623         else
1624                 return odm->rzedy[rzad - 1][2];
1625 }
1626
1627 static char* pl_append(char* buffer, char* str)
1628 {
1629         strcpy(buffer, str);
1630         buffer += strlen(str); 
1631         return buffer;
1632 }
1633
1634 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1635 {    
1636         char file_name[255] = "digits/";
1637         strcat(file_name, fn);
1638         ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
1639         if (!ast_streamfile(chan, file_name, language)) {
1640                 if ((audiofd > -1) && (ctrlfd > -1))
1641                         ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1642                 else
1643                         ast_waitstream(chan, ints);
1644         }
1645         ast_stopstream(chan);
1646 }
1647
1648 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1649 {
1650         /* Initialise variables to allow compilation on Debian-stable, etc */
1651         int m1000E6 = 0;
1652         int i1000E6 = 0;
1653         int m1000E3 = 0;
1654         int i1000E3 = 0;
1655         int m1000 = 0;
1656         int i1000 = 0;
1657         int m100 = 0;
1658         int i100 = 0;
1659         
1660         if (i == 0 && rzad > 0) { 
1661                 return;
1662         }
1663         if (i == 0) {
1664                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1665         }
1666
1667         m1000E6 = i % 1000000000;
1668         i1000E6 = i / 1000000000;
1669
1670         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1671
1672         m1000E3 = m1000E6 % 1000000;
1673         i1000E3 = m1000E6 / 1000000;
1674
1675         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1676
1677         m1000 = m1000E3 % 1000;
1678         i1000 = m1000E3 / 1000;
1679
1680         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1681
1682         m100 = m1000 % 100;
1683         i100 = m1000 / 100;
1684         
1685         if (i100>0)
1686                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1687
1688         if ( m100 > 0 && m100 <=9 ) {
1689                 if (m1000>0)
1690                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1691                 else
1692                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1693         } else if (m100 % 10 == 0) {
1694                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1695         } else if (m100 <= 19 ) {
1696                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1697         } else if (m100 != 0) {
1698                 if (odm->separator_dziesiatek[0]==' ') {
1699                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1700                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1701                 } else {
1702                         char buf[10];
1703                         char *b = buf;
1704                         b = pl_append(b, odm->dziesiatki[m100 / 10]);  
1705                         b = pl_append(b, odm->separator_dziesiatek);  
1706                         b = pl_append(b, odm->cyfry2[m100 % 10]); 
1707                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1708                 }
1709         } 
1710
1711         if (rzad > 0) {
1712                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1713         }
1714 }
1715
1716 /* ast_say_number_full_pl: Polish syntax */
1717 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)
1718 /*
1719 Sounds needed:
1720 0               zero
1721 1               jeden
1722 10              dziesiec
1723 100             sto
1724 1000            tysiac
1725 1000000         milion
1726 1000000000      miliard
1727 1000000000.2    miliardy
1728 1000000000.5    miliardow
1729 1000000.2       miliony
1730 1000000.5       milionow
1731 1000.2          tysiace
1732 1000.5          tysiecy
1733 100m            stu
1734 10m             dziesieciu
1735 11              jedenascie
1736 11m             jedenastu
1737 12              dwanascie
1738 12m             dwunastu
1739 13              trzynascie
1740 13m             trzynastu
1741 14              czternascie
1742 14m             czternastu
1743 15              pietnascie
1744 15m             pietnastu
1745 16              szesnascie
1746 16m             szesnastu
1747 17              siedemnascie
1748 17m             siedemnastu
1749 18              osiemnascie
1750 18m             osiemnastu
1751 19              dziewietnascie
1752 19m             dziewietnastu
1753 1z              jedna
1754 2               dwie
1755 20              dwadziescia
1756 200             dwiescie
1757 200m            dwustu
1758 20m             dwudziestu
1759 2-1m            dwaj
1760 2-2m            dwoch
1761 2z              dwie
1762 3               trzy
1763 30              trzydziesci
1764 300             trzysta
1765 300m            trzystu
1766 30m             trzydziestu
1767 3-1m            trzej
1768 3-2m            trzech
1769 4               cztery
1770 40              czterdziesci
1771 400             czterysta
1772 400m            czterystu
1773 40m             czterdziestu
1774 4-1m            czterej
1775 4-2m            czterech
1776 5               piec
1777 50              piecdziesiat
1778 500             piecset
1779 500m            pieciuset
1780 50m             piedziesieciu
1781 5m              pieciu
1782 6               szesc
1783 60              szescdziesiat
1784 600             szescset
1785 600m            szesciuset
1786 60m             szescdziesieciu
1787 6m              szesciu
1788 7               siedem
1789 70              siedemdziesiat
1790 700             siedemset
1791 700m            siedmiuset
1792 70m             siedemdziesieciu
1793 7m              siedmiu
1794 8               osiem
1795 80              osiemdziesiat
1796 800             osiemset
1797 800m            osmiuset
1798 80m             osiemdziesieciu
1799 8m              osmiu
1800 9               dziewiec
1801 90              dziewiecdziesiat
1802 900             dziewiecset
1803 900m            dziewieciuset
1804 90m             dziewiedziesieciu
1805 9m              dziewieciu
1806 and combinations of eg.: 20_1, 30m_3m, etc...
1807
1808 */
1809 {
1810         char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1811
1812         char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1813
1814         char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m",  /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1815
1816         char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1817
1818         char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1819
1820         char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1821
1822         char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1823
1824         char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1825
1826         char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1827
1828         char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1829
1830         char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1831
1832         char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1833
1834         char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 
1835
1836         /* Initialise variables to allow compilation on Debian-stable, etc */
1837         odmiana *o;
1838
1839         static odmiana *odmiana_nieosobowa = NULL; 
1840         static odmiana *odmiana_meska = NULL; 
1841         static odmiana *odmiana_zenska = NULL; 
1842
1843         if (odmiana_nieosobowa == NULL) {
1844                 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
1845
1846                 odmiana_nieosobowa->separator_dziesiatek = "_";
1847
1848                 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1849                 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1850                 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1851                 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1852                 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1853                 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1854         }
1855
1856         if (odmiana_zenska == NULL) {
1857                 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
1858
1859                 odmiana_zenska->separator_dziesiatek = " ";
1860
1861                 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
1862                 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
1863                 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
1864                 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
1865                 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
1866                 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
1867         }
1868
1869         if (odmiana_meska == NULL) {
1870                 odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
1871
1872                 odmiana_meska->separator_dziesiatek = " ";
1873
1874                 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
1875                 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
1876                 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
1877                 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
1878                 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
1879                 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
1880         }
1881
1882         if (options) {
1883                 if (strncasecmp(options, "f", 1) == 0)
1884                         o = odmiana_zenska;
1885                 else if (strncasecmp(options, "m", 1) == 0)
1886                         o = odmiana_meska;
1887                 else
1888                         o = odmiana_nieosobowa;
1889         } else
1890                 o = odmiana_nieosobowa;
1891
1892         powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
1893         return 0;
1894 }
1895
1896 /* ast_say_number_full_pt: Portuguese syntax */
1897 /*      Extra sounds needed: */
1898 /*      For feminin all sound files end with F */
1899 /*      100E for 100+ something */
1900 /*      1000000S for plural */
1901 /*      pt-e for 'and' */
1902 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)
1903 {
1904         int res = 0;
1905         int playh = 0;
1906         int mf = 1;                            /* +1 = male; -1 = female */
1907         char fn[256] = "";
1908
1909         if (!num) 
1910                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1911
1912         if (options && !strncasecmp(options, "f",1))
1913                 mf = -1;
1914
1915         while(!res && num ) {
1916                 if (num < 0) {
1917                         snprintf(fn, sizeof(fn), "digits/minus");
1918                         if ( num > INT_MIN ) {
1919                                 num = -num;
1920                         } else {
1921                                 num = 0;
1922                         }       
1923                 } else if (num < 20) {
1924                         if ((num == 1 || num == 2) && (mf < 0))
1925                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
1926                         else
1927                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1928                         num = 0;
1929                 } else if (num < 100) {
1930                         snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
1931                         if (num % 10)
1932                                 playh = 1;
1933                         num = num % 10;
1934                 } else if (num < 1000) {
1935                         if (num == 100)
1936                                 snprintf(fn, sizeof(fn), "digits/100");
1937                         else if (num < 200)
1938                                 snprintf(fn, sizeof(fn), "digits/100E");
1939                         else {
1940                                 if (mf < 0 && num > 199)
1941                                         snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
1942                                 else
1943                                         snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
1944                                 if (num % 100)
1945                                         playh = 1;
1946                         }
1947                         num = num % 100;
1948                 } else if (num < 1000000) {
1949                         if (num > 1999) {
1950                                 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
1951                                 if (res)
1952                                         return res;
1953                         }
1954                         snprintf(fn, sizeof(fn), "digits/1000");
1955                         if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
1956                                 playh = 1;
1957                         num = num % 1000;
1958                 } else if (num < 1000000000) {
1959                         res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
1960                         if (res)
1961                                 return res;
1962                         if (num < 2000000)
1963                                 snprintf(fn, sizeof(fn), "digits/1000000");
1964                         else
1965                                 snprintf(fn, sizeof(fn), "digits/1000000S");
1966  
1967                         if ((num % 1000000) &&
1968                                 /* no thousands */
1969                                 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
1970                                 /* no hundreds and below */
1971                                 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
1972                                 playh = 1;
1973                         num = num % 1000000;
1974                 }
1975                 if (!res) {
1976                         if (!ast_streamfile(chan, fn, language)) {
1977                                 if ((audiofd > -1) && (ctrlfd > -1))
1978                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 
1979                                 else
1980                                         res = ast_waitstream(chan, ints);
1981                         }
1982                         ast_stopstream(chan);
1983                 }
1984                 if (!res && playh) {
1985                         res = wait_file(chan, ints, "digits/pt-e", language);
1986                         ast_stopstream(chan);
1987                         playh = 0;
1988                 }
1989         }
1990         return res;
1991 }
1992
1993 /*--- ast_say_number_full_se: Swedish syntax */
1994 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)
1995 {
1996         int res = 0;
1997         int playh = 0;
1998         char fn[256] = "";
1999         int cn = 1;             /* +1 = commune; -1 = neuter */
2000         if (!num) 
2001                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2002         if (options && !strncasecmp(options, "n",1)) cn = -1;
2003
2004         while(!res && (num || playh)) {
2005                 if (num < 0) {
2006                         snprintf(fn, sizeof(fn), "digits/minus");
2007                         if ( num > INT_MIN ) {
2008                                 num = -num;
2009                         } else {
2010                                 num = 0;
2011                         }       
2012                 } else if (playh) {
2013                         snprintf(fn, sizeof(fn), "digits/hundred");
2014                         playh = 0;
2015                 } else if (num < 20) {
2016                         snprintf(fn, sizeof(fn), "digits/%d", num);
2017                         num = 0;
2018                 } else if (num < 100) {
2019                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2020                         num -= ((num / 10) * 10);
2021                 } else if (num == 1 && cn == -1) {      /* En eller ett? */
2022                         snprintf(fn, sizeof(fn), "digits/1N");
2023                         num = 0;
2024                 } else {
2025                         if (num < 1000){
2026                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2027                                 playh++;
2028                                 num -= ((num / 100) * 100);
2029                         } else {
2030                                 if (num < 1000000) { /* 1,000,000 */
2031                                         res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2032                                         if (res) {
2033                                                 return res;
2034                                         }
2035                                         num = num % 1000;
2036                                         snprintf(fn, sizeof(fn), "digits/thousand");
2037                                 } else {
2038                                         if (num < 1000000000) { /* 1,000,000,000 */
2039                                                 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2040                                                 if (res) {
2041                                                         return res;
2042                                                 }
2043                                                 num = num % 1000000;
2044                                                 snprintf(fn, sizeof(fn), "digits/million");
2045                                         } else {
2046                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2047                                                 res = -1;
2048                                         }
2049                                 }
2050                         }
2051                 }
2052                 if (!res) {
2053                         if(!ast_streamfile(chan, fn, language)) {
2054                                 if ((audiofd > -1) && (ctrlfd > -1))
2055                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2056                                 else
2057                                         res = ast_waitstream(chan, ints);
2058                                 ast_stopstream(chan);
2059                         }
2060                 }
2061         }
2062         return res;
2063 }
2064
2065 /*--- ast_say_number_full_tw: Taiwanese syntax */
2066 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2067 {
2068         int res = 0;
2069         int playh = 0;
2070         char fn[256] = "";
2071         if (!num)
2072                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2073
2074         while(!res && (num || playh)) {
2075                         if (num < 0) {
2076                                 snprintf(fn, sizeof(fn), "digits/minus");
2077                                 if ( num > INT_MIN ) {
2078                                         num = -num;
2079                                 } else {
2080                                         num = 0;
2081                                 }       
2082                         } else if (playh) {
2083                                 snprintf(fn, sizeof(fn), "digits/hundred");
2084                                 playh = 0;
2085                         } else  if (num < 10) {
2086                                 snprintf(fn, sizeof(fn), "digits/%d", num);
2087                                 num = 0;
2088                         } else  if (num < 100) {
2089                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2090                                 num -= ((num / 10) * 10);
2091                         } else {
2092                                 if (num < 1000){
2093                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2094                                         playh++;
2095                                         num -= ((num / 100) * 100);
2096                                 } else {
2097                                         if (num < 1000000) { /* 1,000,000 */
2098                                                 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
2099                                                 if (res)
2100                                                         return res;
2101                                                 num = num % 1000;
2102                                                 snprintf(fn, sizeof(fn), "digits/thousand");
2103                                         } else {
2104                                                 if (num < 1000000000) { /* 1,000,000,000 */
2105                                                         res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2106                                                         if (res)
2107                                                                 return res;
2108                                                         num = num % 1000000;
2109                                                         snprintf(fn, sizeof(fn), "digits/million");
2110                                                 } else {
2111                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2112                                                         res = -1;
2113                                                 }
2114                                         }
2115                                 }
2116                         }
2117                         if (!res) {
2118                                 if(!ast_streamfile(chan, fn, language)) {
2119                                         if ((audiofd > -1) && (ctrlfd > -1))
2120                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2121                                         else
2122                                                 res = ast_waitstream(chan, ints);
2123                                 }
2124                                 ast_stopstream(chan);
2125                         }
2126         }
2127         return res;
2128 }
2129
2130 /*--- ast_say_enumeration_full: call language-specific functions */
2131 /* Called from AGI */
2132 int ast_say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2133 {
2134         if (!strcasecmp(language,"en") ) {      /* English syntax */
2135            return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2136         } else if (!strcasecmp(language, "de") ) {      /* German syntax */
2137            return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2138         } 
2139         
2140         /* Default to english */
2141         return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2142 }
2143
2144 /*--- ast_say_enumeration: call language-specific functions without file descriptors */
2145 int ast_say_enumeration(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
2146 {
2147         return(ast_say_enumeration_full(chan, num, ints, language, options, -1, -1));
2148 }
2149
2150 /*--- ast_say_enumeration_full_en: English syntax */
2151 /* This is the default syntax, if no other syntax defined in this file is used */
2152 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2153 {
2154         int res = 0, t = 0;
2155         char fn[256] = "";
2156         
2157         while(!res && num) {
2158                 if (num < 0) {
2159                         snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2160                         if ( num > INT_MIN ) {
2161                                 num = -num;
2162                         } else {
2163                                 num = 0;
2164                         }       
2165                 } else if (num < 20) {
2166                         snprintf(fn, sizeof(fn), "digits/h-%d", num);
2167                         num = 0;
2168                 } else if (num < 100) { 
2169                         int tens = num / 10;
2170                         num = num % 10;
2171                         if (num == 0) {
2172                                 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2173                         } else {
2174                                 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2175                         }
2176                 } else if (num < 1000) {
2177                         int hundreds = num / 100;
2178                         num = num % 100;
2179                         if (hundreds > 1 || t == 1) {
2180                                 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2181                         }                       
2182                         if (res)
2183                                 return res;
2184                         if (num) {
2185                                 snprintf(fn, sizeof(fn), "digits/hundred");
2186                         } else {
2187                                 snprintf(fn, sizeof(fn), "digits/h-hundred");
2188                         }
2189                 } else if (num < 1000000) {
2190                         int thousands = num / 1000;
2191                         num = num % 1000;
2192                         if (thousands > 1 || t == 1) {
2193                                 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2194                         }
2195                         if (res)
2196                                 return res;
2197                         if (num) {                                      
2198                                 snprintf(fn, sizeof(fn), "digits/thousand");
2199                         } else {
2200                                 snprintf(fn, sizeof(fn), "digits/h-thousand");
2201                         }
2202                         t = 1;
2203                 } else if (num < 1000000000) {
2204                         int millions = num / 1000000;
2205                         num = num % 1000000;
2206                         t = 1;
2207                         res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2208                         if (res)
2209                                 return res;
2210                         if (num) {                                      
2211                                 snprintf(fn, sizeof(fn), "digits/million");
2212                         } else {
2213                                 snprintf(fn, sizeof(fn), "digits/h-million");
2214                         }
2215                 } else if (num < INT_MAX) {
2216                         int billions = num / 1000000000;
2217                         num = num % 1000000000;
2218                         t = 1;
2219                         res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2220                         if (res)
2221                                 return res;
2222                         if (num) {                                      
2223                                 snprintf(fn, sizeof(fn), "digits/billion");
2224                         } else {
2225                                 snprintf(fn, sizeof(fn), "digits/h-billion");
2226                         }
2227                 } else if (num == INT_MAX) {
2228                         snprintf(fn, sizeof(fn), "digits/h-last");
2229                         num = 0;
2230                 } else {
2231                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2232                         res = -1;
2233                 }
2234
2235                 if (!res) {
2236                         if (!ast_streamfile(chan, fn, language)) {
2237                                 if ((audiofd > -1) && (ctrlfd > -1)) {
2238                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2239                                 } else {
2240                                         res = ast_waitstream(chan, ints);
2241                                 }
2242                         }
2243                         ast_stopstream(chan);
2244                 }
2245         }
2246         return res;
2247 }
2248
2249 /*--- ast_say_enumeration_full_de: German syntax */
2250 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)
2251 {
2252         /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2253         int res = 0, t = 0;
2254         char fn[256] = "", fna[256] = "";
2255         char *gender;
2256
2257         if (options && !strncasecmp(options, "f",1)) {
2258                 gender = "F";
2259         } else if (options && !strncasecmp(options, "n",1)) {
2260                 gender = "N";
2261         } else {
2262                 gender = "";
2263         }
2264
2265         if (!num) 
2266                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2267
2268         while(!res && num) {
2269                 if (num < 0) {
2270                         snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2271                         if ( num > INT_MIN ) {
2272                                 num = -num;
2273                         } else {
2274                                 num = 0;
2275                         }       
2276                 } else if (num < 100 && t) {
2277                         snprintf(fn, sizeof(fn), "digits/and");
2278                         t = 0;
2279                 } else if (num < 20) {
2280                         snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2281                         num = 0;
2282                 } else if (num < 100) {
2283                         int ones = num % 10;
2284                         if (ones) {
2285                                 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2286                                 num -= ones;
2287                         } else {
2288                                 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2289                                 num = 0;
2290                         }
2291                 } else if (num == 100 && t == 0) {
2292                         snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2293                         num = 0;
2294                 } else if (num < 1000) {
2295                         int hundreds = num / 100;
2296                         num = num % 100;
2297                         if (hundreds == 1) {
2298                                 snprintf(fn, sizeof(fn), "digits/1N");
2299                         } else {
2300                                 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2301                         }
2302                         if (num) {                                      
2303                                 snprintf(fna, sizeof(fna), "digits/hundred");
2304                         } else {
2305                                 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2306                         }
2307                         t = 1;
2308                 } else  if (num < 1000000) {
2309                         int thousands = num / 1000;
2310                         num = num % 1000;
2311                         if (thousands == 1) {
2312                                 if (num) {                                      
2313                                         snprintf(fn, sizeof(fn), "digits/1N");
2314                                         snprintf(fna, sizeof(fna), "digits/thousand");
2315                                 } else {
2316                                         if (t) {
2317                                                 snprintf(fn, sizeof(fn), "digits/1N");
2318                                                 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2319                                         } else {
2320                                                 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2321                                         }
2322                                 }
2323                         } else {
2324                                 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2325                                 if (res) {
2326                                         return res;
2327                                 }
2328                                 if (num) {                                      
2329                                         snprintf(fn, sizeof(fn), "digits/thousand");
2330                                 } else {
2331                                         snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2332                                 }
2333                         }
2334                         t = 1;
2335                 } else if (num < 1000000000) {
2336                         int millions = num / 1000000;
2337                         num = num % 1000000;
2338                         if (millions == 1) {
2339                                 if (num) {                                      
2340                                         snprintf(fn, sizeof(fn), "digits/1F");
2341                                         snprintf(fna, sizeof(fna), "digits/million");
2342                                 } else {
2343                                         snprintf(fn, sizeof(fn), "digits/1N");
2344                                         snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2345                                 }
2346                         } else {
2347                                 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2348                                 if (res) {
2349                                         return res;
2350                                 }
2351                                 if (num) {                                      
2352                                         snprintf(fn, sizeof(fn), "digits/millions");
2353                                 } else {
2354                                         snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2355                                 }
2356                         }
2357                         t = 1;
2358                 } else if (num < INT_MAX) {
2359                         int billions = num / 1000000000;
2360                         num = num % 1000000000;
2361                         if (billions == 1) {
2362                                 if (num) {                                      
2363                                         snprintf(fn, sizeof(fn), "digits/1F");
2364                                         snprintf(fna, sizeof(fna), "digits/milliard");
2365                                 } else {
2366                                         snprintf(fn, sizeof(fn), "digits/1N");
2367                                         snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2368                                 }
2369                         } else {
2370                                 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2371                                 if (res)
2372                                         return res;
2373                                 if (num) {                                      
2374                                         snprintf(fn, sizeof(fna), "digits/milliards");
2375                                 } else {
2376                                         snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2377                                 }
2378                         }
2379                         t = 1;
2380                 } else if (num == INT_MAX) {
2381                         snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2382                         num = 0;
2383                 } else {
2384                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2385                         res = -1;
2386                 }
2387
2388                 if (!res) {
2389                         if (!ast_streamfile(chan, fn, language)) {
2390                                 if ((audiofd > -1) && (ctrlfd > -1)) 
2391                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2392                                 else  
2393                                         res = ast_waitstream(chan, ints);
2394                         }
2395                         ast_stopstream(chan);
2396                         if (!res) {
2397                                 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2398                                         if ((audiofd > -1) && (ctrlfd > -1)) {
2399                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2400                                         } else {
2401                                                 res = ast_waitstream(chan, ints);
2402                                         }
2403                                 }
2404                                 ast_stopstream(chan);
2405                                 strcpy(fna, "");
2406                         }
2407                 }
2408         }
2409         return res;
2410 }
2411
2412 int ast_say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2413 {
2414         if (!strcasecmp(lang, "en") ) { /* English syntax */
2415                 return(ast_say_date_en(chan, t, ints, lang));
2416         } else if (!strcasecmp(lang, "de") ) {  /* German syntax */
2417                 return(ast_say_date_de(chan, t, ints, lang));
2418         } else if (!strcasecmp(lang, "fr") ) {  /* French syntax */
2419                 return(ast_say_date_fr(chan, t, ints, lang));
2420         } else if (!strcasecmp(lang, "nl") ) {  /* Dutch syntax */
2421                 return(ast_say_date_nl(chan, t, ints, lang));
2422         } else if (!strcasecmp(lang, "pt") ) {  /* Portuguese syntax */
2423                 return(ast_say_date_pt(chan, t, ints, lang));
2424         } else if (!strcasecmp(lang, "gr") ) {                          /* Greek syntax */
2425                 return(ast_say_date_gr(chan, t, ints, lang));
2426         }
2427
2428         /* Default to English */
2429         return(ast_say_date_en(chan, t, ints, lang));
2430 }
2431
2432 /* English syntax */
2433 int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2434 {
2435         struct tm tm;
2436         char fn[256];
2437         int res = 0;
2438         ast_localtime(&t,&tm,NULL);
2439         if (!res) {
2440                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2441                 res = ast_streamfile(chan, fn, lang);
2442                 if (!res)
2443                         res = ast_waitstream(chan, ints);
2444         }
2445         if (!res) {
2446                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2447                 res = ast_streamfile(chan, fn, lang);
2448                 if (!res)
2449                         res = ast_waitstream(chan, ints);
2450         }
2451         if (!res)
2452                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2453         if (!res)
2454                 res = ast_waitstream(chan, ints);
2455         if (!res)
2456                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2457         return res;
2458 }
2459
2460 /* German syntax */
2461 int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2462 {
2463         struct tm tm;
2464         char fn[256];
2465         int res = 0;
2466         ast_localtime(&t,&tm,NULL);
2467         if (!res) {
2468                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2469                 res = ast_streamfile(chan, fn, lang);
2470                 if (!res)
2471                         res = ast_waitstream(chan, ints);
2472         }
2473         if (!res)
2474                 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2475         if (!res)
2476                 res = ast_waitstream(chan, ints);
2477         if (!res) {
2478                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2479                 res = ast_streamfile(chan, fn, lang);
2480                 if (!res)
2481                         res = ast_waitstream(chan, ints);
2482         }
2483         if (!res) {
2484                 /* Year */
2485                 int year = tm.tm_year + 1900;
2486                 if (year > 1999) {      /* year 2000 and later */
2487                         res = ast_say_number(chan, year, ints, lang, (char *) NULL);    
2488                 } else {
2489                         if (year < 1100) {
2490                                 /* I'm not going to handle 1100 and prior */
2491                                 /* We'll just be silent on the year, instead of bombing out. */
2492                         } else {
2493                             /* year 1100 to 1999. will anybody need this?!? */
2494                             /* say 1967 as 'neunzen hundert sieben und sechzig' */
2495                                 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) );
2496                                 res = wait_file(chan, ints, fn, lang);
2497                                 if (!res) {
2498                                         res = wait_file(chan,ints, "digits/hundred", lang);
2499                                         if (!res && year % 100 != 0) {
2500                                                 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);    
2501                                         }
2502                                 }
2503                         }
2504                 }
2505         }
2506         return res;
2507 }
2508
2509 /* French syntax */
2510 int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2511 {
2512         struct tm tm;
2513         char fn[256];
2514         int res = 0;
2515         ast_localtime(&t,&tm,NULL);
2516         if (!res) {
2517                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2518                 res = ast_streamfile(chan, fn, lang);
2519                 if (!res)
2520                         res = ast_waitstream(chan, ints);
2521         }
2522         if (!res)
2523                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2524         if (!res)
2525                 res = ast_waitstream(chan, ints);
2526         if (!res) {
2527                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2528                 res = ast_streamfile(chan, fn, lang);
2529                 if (!res)
2530                         res = ast_waitstream(chan, ints);
2531         }
2532         if (!res)
2533                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2534         return res;
2535 }
2536
2537 /* Dutch syntax */
2538 int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2539 {
2540         struct tm tm;
2541         char fn[256];
2542         int res = 0;
2543         ast_localtime(&t,&tm,NULL);
2544         if (!res) {
2545                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2546                 res = ast_streamfile(chan, fn, lang);
2547                 if (!res)
2548                         res = ast_waitstream(chan, ints);
2549         }
2550         if (!res)
2551                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2552         if (!res) {
2553                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2554                 res = ast_streamfile(chan, fn, lang);
2555                 if (!res)
2556                         res = ast_waitstream(chan, ints);
2557         }
2558         if (!res)
2559                 res = ast_waitstream(chan, ints);
2560         if (!res)
2561                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2562         return res;
2563 }
2564
2565 /* Portuguese syntax */
2566 int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2567 {
2568         struct tm tm;
2569         char fn[256];
2570         int res = 0;
2571         ast_localtime(&t,&tm,NULL);
2572         localtime_r(&t,&tm);
2573         snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2574         if (!res)
2575                 res = wait_file(chan, ints, fn, lang);
2576         if (!res)
2577                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
2578         if (!res)
2579                 res = wait_file(chan, ints, "digits/pt-de", lang);
2580         snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2581         if (!res)
2582                 res = wait_file(chan, ints, fn, lang);
2583         if (!res)
2584                 res = wait_file(chan, ints, "digits/pt-de", lang);
2585         if (!res)
2586                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2587
2588         return res;
2589 }
2590
2591 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)
2592 {
2593         if (!strcasecmp(lang, "en") ) { /* English syntax */
2594                 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2595         } else if (!strcasecmp(lang, "de") ) {  /* German syntax */
2596                 return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone));
2597         } else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) {        /* Spanish syntax */
2598                 return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone));
2599         } else if (!strcasecmp(lang, "fr") ) {  /* French syntax */
2600                 return(ast_say_date_with_format_fr(chan, time, ints, lang, format, timezone));
2601         } else if (!strcasecmp(lang, "it") ) {  /* Italian syntax */
2602                 return(ast_say_date_with_format_it(chan, time, ints, lang, format, timezone));
2603         } else if (!strcasecmp(lang, "nl") ) {  /* Dutch syntax */
2604                 return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone));
2605         } else if (!strcasecmp(lang, "pt") ) {  /* Portuguese syntax */
2606                 return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone));
2607         } else if (!strcasecmp(lang, "tw") ) {  /* Taiwanese syntax */
2608                 return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone));
2609         } else if (!strcasecmp(lang, "gr") ) {                          /* Greek syntax */
2610                 return(ast_say_date_with_format_gr(chan, time, ints, lang, format, timezone));
2611         }
2612
2613         /* Default to English */
2614         return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2615 }
2616
2617 /* English syntax */
2618 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)
2619 {
2620         struct tm tm;
2621         int res=0, offset, sndoffset;
2622         char sndfile[256], nextmsg[256];
2623
2624         ast_localtime(&time,&tm,timezone);
2625
2626         for (offset=0 ; format[offset] != '\0' ; offset++) {
2627                 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
2628                 switch (format[offset]) {
2629                         /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
2630                         case '\'':
2631                                 /* Literal name of a sound file */
2632                                 sndoffset=0;
2633                                 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
2634                                         sndfile[sndoffset] = format[offset];
2635                                 sndfile[sndoffset] = '\0';
2636                                 res = wait_file(chan,ints,sndfile,lang);
2637                                 break;
2638                         case 'A':
2639                         case 'a':
2640                                 /* Sunday - Saturday */
2641                                 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
2642                                 res = wait_file(chan,ints,nextmsg,lang);
2643                                 break;
2644                         case 'B':
2645                         case 'b':
2646                         case 'h':
2647                                 /* January - December */
2648                                 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
2649                                 res = wait_file(chan,ints,nextmsg,lang);
2650                                 break;
2651                         case 'm':
2652                                 /* Month enumerated */
2653                                 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, (char *) NULL);    
2654                                 break;
2655                         case 'd':
2656                         case 'e':
2657                                 /* First - Thirtyfirst */
2658                                 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char *) NULL); 
2659                                 break;
2660                         case 'Y':
2661                                 /* Year */
2662                                 if (tm.tm_year > 99) {
2663                                         res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2664                                 } else {
2665                                         if (tm.tm_year < 1) {
2666                                                 /* I'm not going to handle 1900 and prior */
2667                                                 /* We'll just be silent on the year, instead of bombing out. */
2668                                         } else {
2669                                                 res = wait_file(chan,ints, "digits/19",lang);
2670                                                 if (!res) {
2671                                                         if (tm.tm_year <= 9) {
2672                                                                 /* 1901 - 1909 */
2673                                                                 res = wait_file(chan,ints, "digits/oh",lang);
2674                                                                 if (!res) {
2675                                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2676                                                                         res = wait_file(chan,ints,nextmsg,lang);
2677                                                                 }
2678                                                         } else if (tm.tm_year <= 20) {
2679                                                                 /* 1910 - 1920 */
2680                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2681                                                                 res = wait_file(chan,ints,nextmsg,lang);
2682                                                         } else {
2683                                                                 /* 1921 - 1999 */
2684                                                                 int ten, one;
2685                                                                 ten = tm.tm_year / 10;
2686                                                                 one = tm.tm_year % 10;
2687                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
2688                                                                 res = wait_file(chan,ints,nextmsg,lang);
2689                                                                 if (!res) {
2690                                                                         if (one != 0) {
2691                                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2692                                                                                 res = wait_file(chan,ints,nextmsg,lang);
2693                                                                         }
2694                                                                 }
2695                                                         }
2696                                                 }
2697                                         }
2698                                 }
2699                                 break;
2700                         case 'I':
2701                         case 'l':
2702                                 /* 12-Hour */
2703                                 if (tm.tm_hour == 0)
2704                                         snprintf(nextmsg,sizeof(nextmsg), "digits/12");
2705                                 else if (tm.tm_hour > 12)
2706                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
2707                                 else
2708                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
2709                                 res = wait_file(chan,ints,nextmsg,lang);
2710                                 break;
2711                         case 'H':
2712                         case 'k':
2713                                 /* 24-Hour */
2714                                 if (format[offset] == 'H') {
2715                                         /* e.g. oh-eight */
2716                                         if (tm.tm_hour < 10) {
2717                                                 res = wait_file(chan,ints, "digits/oh",lang);
2718                                         }
2719                                 } else {
2720                                         /* e.g. eight */
2721                                         if (tm.tm_hour == 0) {
2722                                                 res = wait_file(chan,ints, "digits/oh",lang);
2723                                         }
2724                                 }
2725                                 if (!res) {
2726                                         if (tm.tm_hour != 0) {
2727                                                 int remainder = tm.tm_hour;
2728                                                 if (tm.tm_hour > 20) {
2729                                                         res = wait_file(chan,ints, "digits/20",lang);
2730                                                         remainder -= 20;
2731                                                 }
2732                                                 if (!res) {
2733                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
2734                                                         res = wait_file(chan,ints,nextmsg,lang);
2735                                                 }
2736                                         }
2737                                 }
2738                                 break;
2739                         case 'M':
2740                                 /* Minute */
2741                                 if (tm.tm_min == 0) {
2742                                         res = wait_file(chan,ints, "digits/oclock",lang);
2743                                 } else if (tm.tm_min < 10) {
2744                                         res = wait_file(chan,ints, "digits/oh",lang);
2745                                         if (!res) {
2746                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2747                                                 res = wait_file(chan,ints,nextmsg,lang);
2748                                         }
2749                                 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
2750                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2751                                         res = wait_file(chan,ints,nextmsg,lang);
2752                                 } else {
2753                                         int ten, one;
2754                                         ten = (tm.tm_min / 10) * 10;
2755                                         one = (tm.tm_min % 10);
2756                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2757                                         res = wait_file(chan,ints,nextmsg,lang);
2758                                         if (!res) {
2759                                           &nbs