Revert Jim's earlier "fix" :)
[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 = 1;                            /* +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 && !strncasecmp(options, "f",1))
1102                 mf = -1;
1103
1104         while (!res && num) {
1105                 if (num < 0) {
1106                         snprintf(fn, sizeof(fn), "digits/minus");
1107                         if ( num > INT_MIN ) {
1108                                 num = -num;
1109                         } else {
1110                                 num = 0;
1111                         }       
1112                 } else if (playa) {
1113                         snprintf(fn, sizeof(fn), "digits/y");
1114                         playa = 0;
1115                 } else if (num == 1) {
1116                         if (mf < 0)
1117                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
1118                         else
1119                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1120                         num = 0;
1121                 } else if (num < 31) {
1122                         snprintf(fn, sizeof(fn), "digits/%d", num);
1123                         num = 0;
1124                 } else if (num < 100) {
1125                         snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1126                         num -= ((num/10)*10);
1127                         if (num)
1128                                 playa++;
1129                 } else if (num == 100) {
1130                         snprintf(fn, sizeof(fn), "digits/cien");
1131                         num = 0;
1132                 } else {
1133                         if (num < 1000) {
1134                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
1135                                 num -= ((num/100)*100);
1136                         } else {
1137                                 if (num < 1000000) {
1138                                         res = ast_say_number_full_es(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1139                                         if (res)
1140                                                 return res;
1141                                         num = num % 1000;
1142                                         snprintf(fn, sizeof(fn), "digits/mil");
1143                                 } else {
1144                                         if (num < 2147483640) {
1145                                                 res = ast_say_number_full_es(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1146                                                 if (res)
1147                                                         return res;
1148                                                 if ((num/1000000) == 1) {
1149                                                         snprintf(fn, sizeof(fn), "digits/millon");
1150                                                 } else {
1151                                                         snprintf(fn, sizeof(fn), "digits/millones");
1152                                                 }
1153                                                 num = num % 1000000;
1154                                         } else {
1155                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1156                                                 res = -1;
1157                                         }
1158                                 }
1159                         }
1160                 }
1161
1162                 if (!res) {
1163                         if(!ast_streamfile(chan, fn, language)) {
1164                                 if ((audiofd > -1) && (ctrlfd > -1))
1165                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1166                                 else
1167                                         res = ast_waitstream(chan, ints);
1168                         }
1169                         ast_stopstream(chan);
1170
1171                 }
1172                         
1173         }
1174         return res;
1175 }
1176
1177 /*--- ast_say_number_full_fr: French syntax */
1178 /*      Extra sounds needed:
1179         1F: feminin 'une'
1180         et: 'and' */
1181 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)
1182 {
1183         int res = 0;
1184         int playh = 0;
1185         int playa = 0;
1186         int mf = 1;                            /* +1 = male; -1 = female */
1187         char fn[256] = "";
1188         if (!num) 
1189                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1190         
1191         if (options && !strncasecmp(options, "f",1))
1192                 mf = -1;
1193
1194         while(!res && (num || playh || playa)) {
1195                 if (num < 0) {
1196                         snprintf(fn, sizeof(fn), "digits/minus");
1197                         if ( num > INT_MIN ) {
1198                                 num = -num;
1199                         } else {
1200                                 num = 0;
1201                         }       
1202                 } else if (playh) {
1203                         snprintf(fn, sizeof(fn), "digits/hundred");
1204                         playh = 0;
1205                 } else if (playa) {
1206                         snprintf(fn, sizeof(fn), "digits/et");
1207                         playa = 0;
1208                 } else if (num == 1) {
1209                         if (mf < 0)
1210                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
1211                         else
1212                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1213                         num = 0;
1214                 } else if (num < 21) {
1215                         snprintf(fn, sizeof(fn), "digits/%d", num);
1216                         num = 0;
1217                 } else if (num < 70) {
1218                         snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
1219                         if ((num % 10) == 1) playa++;
1220                         num = num % 10;
1221                 } else if (num < 80) {
1222                         snprintf(fn, sizeof(fn), "digits/60");
1223                         if ((num % 10) == 1) playa++;
1224                         num = num - 60;
1225                 } else if (num < 100) {
1226                         snprintf(fn, sizeof(fn), "digits/80");
1227                         num = num - 80;
1228                 } else if (num < 200) {
1229                         snprintf(fn, sizeof(fn), "digits/hundred");
1230                         num = num - 100;
1231                 } else if (num < 1000) {
1232                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1233                         playh++;
1234                         num = num % 100;
1235                 } else if (num < 2000) {
1236                         snprintf(fn, sizeof(fn), "digits/thousand");
1237                         num = num - 1000;
1238                 } else if (num < 1000000) {
1239                         res = ast_say_number_full_fr(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1240                         if (res)
1241                                 return res;
1242                         snprintf(fn, sizeof(fn), "digits/thousand");
1243                         num = num % 1000;
1244                 } else  if (num < 1000000000) {
1245                         res = ast_say_number_full_fr(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1246                         if (res)
1247                                 return res;
1248                         snprintf(fn, sizeof(fn), "digits/million");
1249                         num = num % 1000000;
1250                 } else {
1251                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1252                         res = -1;
1253                 }
1254                 if (!res) {
1255                         if(!ast_streamfile(chan, fn, language)) {
1256                                 if ((audiofd > -1) && (ctrlfd > -1))
1257                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1258                                 else
1259                                         res = ast_waitstream(chan, ints);
1260                         }
1261                         ast_stopstream(chan);
1262                 }
1263         }
1264         return res;
1265 }
1266
1267 /*--- ast_say_number_full_it:  Italian */
1268 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1269 {
1270         int res = 0;
1271         int playh = 0;
1272         int tempnum = 0;
1273         char fn[256] = "";
1274
1275         if (!num)
1276                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1277
1278                 /*
1279                 Italian support
1280
1281                 Like english, numbers up to 20 are a single 'word', and others
1282                 compound, but with exceptions.
1283                 For example 21 is not twenty-one, but there is a single word in 'it'.
1284                 Idem for 28 (ie when a the 2nd part of a compund number
1285                 starts with a vowel)
1286
1287                 There are exceptions also for hundred, thousand and million.
1288                 In english 100 = one hundred, 200 is two hundred.
1289                 In italian 100 = cento , like to say hundred (without one),
1290                 200 and more are like english.
1291                 
1292                 Same applies for thousand:
1293                 1000 is one thousand in en, 2000 is two thousand.
1294                 In it we have 1000 = mille , 2000 = 2 mila 
1295
1296                 For million(s) we use the plural, if more than one
1297                 Also, one million is abbreviated in it, like on-million,
1298                 or 'un milione', not 'uno milione'.
1299                 So the right file is provided.
1300                 */
1301
1302                 while(!res && (num || playh)) {
1303                         if (num < 0) {
1304                                 snprintf(fn, sizeof(fn), "digits/minus");
1305                                 if ( num > INT_MIN ) {
1306                                         num = -num;
1307                                 } else {
1308                                         num = 0;
1309                                 }       
1310                         } else if (playh) {
1311                                 snprintf(fn, sizeof(fn), "digits/hundred");
1312                                 playh = 0;
1313                         } else if (num < 20) {
1314                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1315                                 num = 0;
1316                         } else if (num == 21) {
1317                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1318                                 num = 0;
1319                         } else if (num == 28) {
1320                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1321                                 num = 0;
1322                         } else if (num == 31) {
1323                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1324                                 num = 0;
1325                         } else if (num == 38) {
1326                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1327                                 num = 0;
1328                         } else if (num == 41) {
1329                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1330                                 num = 0;
1331                         } else if (num == 48) {
1332                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1333                                 num = 0;
1334                         } else if (num == 51) {
1335                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1336                                 num = 0;
1337                         } else if (num == 58) {
1338                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1339                                 num = 0;
1340                         } else if (num == 61) {
1341                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1342                                 num = 0;
1343                         } else if (num == 68) {
1344                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1345                                 num = 0;
1346                         } else if (num == 71) {
1347                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1348                                 num = 0;
1349                         } else if (num == 78) {
1350                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1351                                 num = 0;
1352                         } else if (num == 81) {
1353                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1354                                 num = 0;
1355                         } else if (num == 88) {
1356                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1357                                 num = 0;
1358                         } else if (num == 91) {
1359                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1360                                 num = 0;
1361                         } else if (num == 98) {
1362                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1363                                 num = 0;
1364                         } else if (num < 100) {
1365                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1366                                 num -= ((num / 10) * 10);
1367                         } else {
1368                                 if (num < 1000) {
1369                                         if ((num / 100) > 1) {
1370                                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1371                                                 playh++;
1372                                         } else {
1373                                                 snprintf(fn, sizeof(fn), "digits/hundred");
1374                                         }
1375                                         num -= ((num / 100) * 100);
1376                                 } else {
1377                                         if (num < 1000000) { /* 1,000,000 */
1378                                                 if ((num/1000) > 1)
1379                                                         res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1380                                                 if (res)
1381                                                         return res;
1382                                                 tempnum = num;
1383                                                 num = num % 1000;
1384                                                 if ((tempnum / 1000) < 2)
1385                                                         snprintf(fn, sizeof(fn), "digits/thousand");
1386                                                 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1387                                                         snprintf(fn, sizeof(fn), "digits/thousands");
1388                                         } else {
1389                                                 if (num < 1000000000) { /* 1,000,000,000 */
1390                                                         if ((num / 1000000) > 1)
1391                                                                 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1392                                                         if (res)
1393                                                                 return res;
1394                                                         tempnum = num;
1395                                                         num = num % 1000000;
1396                                                         if ((tempnum / 1000000) < 2)
1397                                                                 snprintf(fn, sizeof(fn), "digits/million");
1398                                                         else
1399                                                                 snprintf(fn, sizeof(fn), "digits/millions");
1400                                                 } else {
1401                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1402                                                         res = -1;
1403                                                 }
1404                                         }
1405                                 }
1406                         }
1407                         if (!res) {
1408                                 if(!ast_streamfile(chan, fn, language)) {
1409                                         if ((audiofd > -1) && (ctrlfd > -1))
1410                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1411                                         else
1412                                                 res = ast_waitstream(chan, ints);
1413                                 }
1414                                 ast_stopstream(chan);
1415                         }
1416                 }
1417         return res;
1418 }
1419
1420 /*--- ast_say_number_full_nl: dutch syntax */
1421 /* New files: digits/nl-en
1422  */
1423 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1424 {
1425         int res = 0;
1426         int playh = 0;
1427         int units = 0;
1428         char fn[256] = "";
1429         if (!num) 
1430                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1431         while (!res && (num || playh )) {
1432                 if (num < 0) {
1433                         snprintf(fn, sizeof(fn), "digits/minus");
1434                         if ( num > INT_MIN ) {
1435                                 num = -num;
1436                         } else {
1437                                 num = 0;
1438                         }       
1439                 } else if (playh) {
1440                         snprintf(fn, sizeof(fn), "digits/hundred");
1441                         playh = 0;
1442                 } else if (num < 20) {
1443                         snprintf(fn, sizeof(fn), "digits/%d", num);
1444                         num = 0;
1445                 } else if (num < 100) {
1446                         units = num % 10;
1447                         if (units > 0) {
1448                                 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1449                                 if (res)
1450                                         return res;
1451                                 num = num - units;
1452                                 snprintf(fn, sizeof(fn), "digits/nl-en");
1453                         } else {
1454                                 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1455                                 num = 0;
1456                         }
1457                 } else {
1458                         if (num < 1000) {
1459                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1460                                 playh++;
1461                                 num -= ((num / 100) * 100);
1462                         } else {
1463                                 if (num < 1000000) { /* 1,000,000 */
1464                                         res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
1465                                         if (res)
1466                                                 return res;
1467                                         num = num % 1000;
1468                                         snprintf(fn, sizeof(fn), "digits/thousand");
1469                                 } else {
1470                                         if (num < 1000000000) { /* 1,000,000,000 */
1471                                                 res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1472                                                 if (res)
1473                                                         return res;
1474                                                 num = num % 1000000;
1475                                                 snprintf(fn, sizeof(fn), "digits/million");
1476                                         } else {
1477                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1478                                                 res = -1;
1479                                         }
1480                                 }
1481                         }
1482                 }
1483
1484                 if (!res) {
1485                         if(!ast_streamfile(chan, fn, language)) {
1486                                 if ((audiofd > -1) && (ctrlfd > -1))
1487                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1488                                 else
1489                                         res = ast_waitstream(chan, ints);
1490                         }
1491                         ast_stopstream(chan);
1492                 }
1493         }
1494         return res;
1495 }
1496
1497 /*--- ast_say_number_full_no: Norwegian syntax */
1498 /* New files:
1499  In addition to American English, the following sounds are required:  "and", "1N"
1500  */
1501 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)
1502 {
1503         int res = 0;
1504         int playh = 0;
1505         int playa = 0;
1506         int cn = 1;             /* +1 = commune; -1 = neuter */
1507         char fn[256] = "";
1508         
1509         if (!num) 
1510                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1511         
1512         if (options && !strncasecmp(options, "n",1)) cn = -1;
1513
1514         while(!res && (num || playh || playa )) {
1515                 /* The grammar for Norwegian numbers is the same as for English except
1516                 * for the following:
1517                 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1518                 *   "and" before the last two digits, i.e. 2034 is "two thousand and
1519                 *   thirty-four" and 1000012 is "one million and twelve".
1520                 */
1521                 if (num < 0) {
1522                         snprintf(fn, sizeof(fn), "digits/minus");
1523                         if ( num > INT_MIN ) {
1524                                 num = -num;
1525                         } else {
1526                                 num = 0;
1527                         }       
1528                 } else if (playh) {
1529                         snprintf(fn, sizeof(fn), "digits/hundred");
1530                         playh = 0;
1531                 } else if (playa) {
1532                         snprintf(fn, sizeof(fn), "digits/and");
1533                         playa = 0;
1534                 } else if (num == 1 && cn == -1) {
1535                         snprintf(fn, sizeof(fn), "digits/1N");
1536                         num = 0;
1537                 } else if (num < 20) {
1538                         snprintf(fn, sizeof(fn), "digits/%d", num);
1539                         num = 0;
1540                 } else if (num < 100) {
1541                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1542                         num -= ((num / 10) * 10);
1543                 } else if (num < 1000) {
1544                         int hundreds = num / 100;
1545                         if (hundreds == 1)
1546                                 snprintf(fn, sizeof(fn), "digits/1N");
1547                         else
1548                                 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1549
1550                         playh++;
1551                         num -= 100 * hundreds;
1552                         if (num)
1553                                 playa++;
1554                 } else  if (num < 1000000) {
1555                         res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1556                         if (res)
1557                                 return res;
1558                         snprintf(fn, sizeof(fn), "digits/thousand");
1559                         num = num % 1000;
1560                         if (num && num < 100)
1561                                 playa++;
1562                 } else  if (num < 1000000000) {
1563                                 int millions = num / 1000000;
1564                                 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1565                                 if (res)
1566                                         return res;
1567                                 snprintf(fn, sizeof(fn), "digits/million");
1568                                 num = num % 1000000;
1569                                 if (num && num < 100)
1570                                         playa++;
1571                 } else {
1572                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1573                                 res = -1;
1574                 }
1575                 
1576                 if (!res) {
1577                         if(!ast_streamfile(chan, fn, language)) {
1578                                 if ((audiofd > -1) && (ctrlfd > -1)) 
1579                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1580                                 else  
1581                                         res = ast_waitstream(chan, ints);
1582                         }
1583                         ast_stopstream(chan);
1584                 }
1585         }
1586         return res;
1587 }
1588
1589 typedef struct {  
1590         char *separator_dziesiatek;
1591         char *cyfry[10];
1592         char *cyfry2[10];
1593         char *setki[10];
1594         char *dziesiatki[10];
1595         char *nastki[10];  
1596         char *rzedy[3][3];
1597 } odmiana;
1598
1599 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1600 {
1601         if (rzad==0)
1602                 return "";
1603  
1604         if (i==1)
1605                 return odm->rzedy[rzad - 1][0];
1606         if ((i > 21 || i < 11) &&  i%10 > 1 && i%10 < 5)
1607                 return odm->rzedy[rzad - 1][1];
1608         else
1609                 return odm->rzedy[rzad - 1][2];
1610 }
1611
1612 static char* pl_append(char* buffer, char* str)
1613 {
1614         strcpy(buffer, str);
1615         buffer += strlen(str); 
1616         return buffer;
1617 }
1618
1619 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1620 {    
1621         char file_name[255] = "digits/";
1622         strcat(file_name, fn);
1623         ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
1624         if (!ast_streamfile(chan, file_name, language)) {
1625                 if ((audiofd > -1) && (ctrlfd > -1))
1626                         ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1627                 else
1628                         ast_waitstream(chan, ints);
1629         }
1630         ast_stopstream(chan);
1631 }
1632
1633 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1634 {
1635         /* Initialise variables to allow compilation on Debian-stable, etc */
1636         int m1000E6 = 0;
1637         int i1000E6 = 0;
1638         int m1000E3 = 0;
1639         int i1000E3 = 0;
1640         int m1000 = 0;
1641         int i1000 = 0;
1642         int m100 = 0;
1643         int i100 = 0;
1644         
1645         if (i == 0 && rzad > 0) { 
1646                 return;
1647         }
1648         if (i == 0) {
1649                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1650         }
1651
1652         m1000E6 = i % 1000000000;
1653         i1000E6 = i / 1000000000;
1654
1655         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1656
1657         m1000E3 = m1000E6 % 1000000;
1658         i1000E3 = m1000E6 / 1000000;
1659
1660         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1661
1662         m1000 = m1000E3 % 1000;
1663         i1000 = m1000E3 / 1000;
1664
1665         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1666
1667         m100 = m1000 % 100;
1668         i100 = m1000 / 100;
1669         
1670         if (i100>0)
1671                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1672
1673         if ( m100 > 0 && m100 <=9 ) {
1674                 if (m1000>0)
1675                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1676                 else
1677                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1678         } else if (m100 % 10 == 0) {
1679                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1680         } else if (m100 <= 19 ) {
1681                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1682         } else if (m100 != 0) {
1683                 if (odm->separator_dziesiatek[0]==' ') {
1684                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1685                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1686                 } else {
1687                         char buf[10];
1688                         char *b = buf;
1689                         b = pl_append(b, odm->dziesiatki[m100 / 10]);  
1690                         b = pl_append(b, odm->separator_dziesiatek);  
1691                         b = pl_append(b, odm->cyfry2[m100 % 10]); 
1692                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1693                 }
1694         } 
1695
1696         if (rzad > 0) {
1697                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1698         }
1699 }
1700
1701 /* ast_say_number_full_pl: Polish syntax */
1702 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)
1703 /*
1704 Sounds needed:
1705 0               zero
1706 1               jeden
1707 10              dziesiec
1708 100             sto
1709 1000            tysiac
1710 1000000         milion
1711 1000000000      miliard
1712 1000000000.2    miliardy
1713 1000000000.5    miliardow
1714 1000000.2       miliony
1715 1000000.5       milionow
1716 1000.2          tysiace
1717 1000.5          tysiecy
1718 100m            stu
1719 10m             dziesieciu
1720 11              jedenascie
1721 11m             jedenastu
1722 12              dwanascie
1723 12m             dwunastu
1724 13              trzynascie
1725 13m             trzynastu
1726 14              czternascie
1727 14m             czternastu
1728 15              pietnascie
1729 15m             pietnastu
1730 16              szesnascie
1731 16m             szesnastu
1732 17              siedemnascie
1733 17m             siedemnastu
1734 18              osiemnascie
1735 18m             osiemnastu
1736 19              dziewietnascie
1737 19m             dziewietnastu
1738 1z              jedna
1739 2               dwie
1740 20              dwadziescia
1741 200             dwiescie
1742 200m            dwustu
1743 20m             dwudziestu
1744 2-1m            dwaj
1745 2-2m            dwoch
1746 2z              dwie
1747 3               trzy
1748 30              trzydziesci
1749 300             trzysta
1750 300m            trzystu
1751 30m             trzydziestu
1752 3-1m            trzej
1753 3-2m            trzech
1754 4               cztery
1755 40              czterdziesci
1756 400             czterysta
1757 400m            czterystu
1758 40m             czterdziestu
1759 4-1m            czterej
1760 4-2m            czterech
1761 5               piec
1762 50              piecdziesiat
1763 500             piecset
1764 500m            pieciuset
1765 50m             piedziesieciu
1766 5m              pieciu
1767 6               szesc
1768 60              szescdziesiat
1769 600             szescset
1770 600m            szesciuset
1771 60m             szescdziesieciu
1772 6m              szesciu
1773 7               siedem
1774 70              siedemdziesiat
1775 700             siedemset
1776 700m            siedmiuset
1777 70m             siedemdziesieciu
1778 7m              siedmiu
1779 8               osiem
1780 80              osiemdziesiat
1781 800             osiemset
1782 800m            osmiuset
1783 80m             osiemdziesieciu
1784 8m              osmiu
1785 9               dziewiec
1786 90              dziewiecdziesiat
1787 900             dziewiecset
1788 900m            dziewieciuset
1789 90m             dziewiedziesieciu
1790 9m              dziewieciu
1791 and combinations of eg.: 20_1, 30m_3m, etc...
1792
1793 */
1794 {
1795         char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1796
1797         char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1798
1799         char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m",  /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1800
1801         char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1802
1803         char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1804
1805         char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1806
1807         char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1808
1809         char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1810
1811         char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1812
1813         char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1814
1815         char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1816
1817         char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1818
1819         char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 
1820
1821         /* Initialise variables to allow compilation on Debian-stable, etc */
1822         odmiana *o;
1823
1824         static odmiana *odmiana_nieosobowa = NULL; 
1825         static odmiana *odmiana_meska = NULL; 
1826         static odmiana *odmiana_zenska = NULL; 
1827
1828         if (odmiana_nieosobowa == NULL) {
1829                 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
1830
1831                 odmiana_nieosobowa->separator_dziesiatek = "_";
1832
1833                 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1834                 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1835                 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1836                 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1837                 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1838                 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1839         }
1840
1841         if (odmiana_zenska == NULL) {
1842                 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
1843
1844                 odmiana_zenska->separator_dziesiatek = " ";
1845
1846                 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
1847                 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
1848                 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
1849                 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
1850                 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
1851                 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
1852         }
1853
1854         if (odmiana_meska == NULL) {
1855                 odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
1856
1857                 odmiana_meska->separator_dziesiatek = " ";
1858
1859                 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
1860                 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
1861                 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
1862                 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
1863                 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
1864                 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
1865         }
1866
1867         if (options) {
1868                 if (strncasecmp(options, "f", 1) == 0)
1869                         o = odmiana_zenska;
1870                 else if (strncasecmp(options, "m", 1) == 0)
1871                         o = odmiana_meska;
1872                 else
1873                         o = odmiana_nieosobowa;
1874         } else
1875                 o = odmiana_nieosobowa;
1876
1877         powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
1878         return 0;
1879 }
1880
1881 /* ast_say_number_full_pt: Portuguese syntax */
1882 /*      Extra sounds needed: */
1883 /*      For feminin all sound files end with F */
1884 /*      100E for 100+ something */
1885 /*      1000000S for plural */
1886 /*      pt-e for 'and' */
1887 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)
1888 {
1889         int res = 0;
1890         int playh = 0;
1891         int mf = 1;                            /* +1 = male; -1 = female */
1892         char fn[256] = "";
1893
1894         if (!num) 
1895                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1896
1897         if (options && !strncasecmp(options, "f",1))
1898                 mf = -1;
1899
1900         while(!res && num ) {
1901                 if (num < 0) {
1902                         snprintf(fn, sizeof(fn), "digits/minus");
1903                         if ( num > INT_MIN ) {
1904                                 num = -num;
1905                         } else {
1906                                 num = 0;
1907                         }       
1908                 } else if (num < 20) {
1909                         if ((num == 1 || num == 2) && (mf < 0))
1910                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
1911                         else
1912                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1913                         num = 0;
1914                 } else if (num < 100) {
1915                         snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
1916                         if (num % 10)
1917                                 playh = 1;
1918                         num = num % 10;
1919                 } else if (num < 1000) {
1920                         if (num == 100)
1921                                 snprintf(fn, sizeof(fn), "digits/100");
1922                         else if (num < 200)
1923                                 snprintf(fn, sizeof(fn), "digits/100E");
1924                         else {
1925                                 if (mf < 0 && num > 199)
1926                                         snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
1927                                 else
1928                                         snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
1929                                 if (num % 100)
1930                                         playh = 1;
1931                         }
1932                         num = num % 100;
1933                 } else if (num < 1000000) {
1934                         if (num > 1999) {
1935                                 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
1936                                 if (res)
1937                                         return res;
1938                         }
1939                         snprintf(fn, sizeof(fn), "digits/1000");
1940                         if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
1941                                 playh = 1;
1942                         num = num % 1000;
1943                 } else if (num < 1000000000) {
1944                         res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
1945                         if (res)
1946                                 return res;
1947                         if (num < 2000000)
1948                                 snprintf(fn, sizeof(fn), "digits/1000000");
1949                         else
1950                                 snprintf(fn, sizeof(fn), "digits/1000000S");
1951  
1952                         if ((num % 1000000) &&
1953                                 /* no thousands */
1954                                 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
1955                                 /* no hundreds and below */
1956                                 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
1957                                 playh = 1;
1958                         num = num % 1000000;
1959                 }
1960                 if (!res && playh) {
1961                         res = wait_file(chan, ints, "digits/pt-e", language);
1962                         ast_stopstream(chan);
1963                         playh = 0;
1964                 }
1965                 if (!res) {
1966                         if (!ast_streamfile(chan, fn, language)) {
1967                                 if ((audiofd > -1) && (ctrlfd > -1))
1968                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 
1969                                 else
1970                                         res = ast_waitstream(chan, ints);
1971                         }
1972                         ast_stopstream(chan);
1973                 }
1974         }
1975         return res;
1976 }
1977
1978 /*--- ast_say_number_full_se: Swedish syntax */
1979 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)
1980 {
1981         int res = 0;
1982         int playh = 0;
1983         char fn[256] = "";
1984         int cn = 1;             /* +1 = commune; -1 = neuter */
1985         if (!num) 
1986                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1987         if (options && !strncasecmp(options, "n",1)) cn = -1;
1988
1989         while(!res && (num || playh)) {
1990                 if (num < 0) {
1991                         snprintf(fn, sizeof(fn), "digits/minus");
1992                         if ( num > INT_MIN ) {
1993                                 num = -num;
1994                         } else {
1995                                 num = 0;
1996                         }       
1997                 } else if (playh) {
1998                         snprintf(fn, sizeof(fn), "digits/hundred");
1999                         playh = 0;
2000                 } else if (num < 20) {
2001                         snprintf(fn, sizeof(fn), "digits/%d", num);
2002                         num = 0;
2003                 } else if (num < 100) {
2004                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2005                         num -= ((num / 10) * 10);
2006                 } else if (num == 1 && cn == -1) {      /* En eller ett? */
2007                         snprintf(fn, sizeof(fn), "digits/1N");
2008                         num = 0;
2009                 } else {
2010                         if (num < 1000){
2011                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2012                                 playh++;
2013                                 num -= ((num / 100) * 100);
2014                         } else {
2015                                 if (num < 1000000) { /* 1,000,000 */
2016                                         res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2017                                         if (res) {
2018                                                 return res;
2019                                         }
2020                                         num = num % 1000;
2021                                         snprintf(fn, sizeof(fn), "digits/thousand");
2022                                 } else {
2023                                         if (num < 1000000000) { /* 1,000,000,000 */
2024                                                 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2025                                                 if (res) {
2026                                                         return res;
2027                                                 }
2028                                                 num = num % 1000000;
2029                                                 snprintf(fn, sizeof(fn), "digits/million");
2030                                         } else {
2031                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2032                                                 res = -1;
2033                                         }
2034                                 }
2035                         }
2036                 }
2037                 if (!res) {
2038                         if(!ast_streamfile(chan, fn, language)) {
2039                                 if ((audiofd > -1) && (ctrlfd > -1))
2040                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2041                                 else
2042                                         res = ast_waitstream(chan, ints);
2043                                 ast_stopstream(chan);
2044                         }
2045                 }
2046         }
2047         return res;
2048 }
2049
2050 /*--- ast_say_number_full_tw: Taiwanese syntax */
2051 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2052 {
2053         int res = 0;
2054         int playh = 0;
2055         char fn[256] = "";
2056         if (!num)
2057                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2058
2059         while(!res && (num || playh)) {
2060                         if (num < 0) {
2061                                 snprintf(fn, sizeof(fn), "digits/minus");
2062                                 if ( num > INT_MIN ) {
2063                                         num = -num;
2064                                 } else {
2065                                         num = 0;
2066                                 }       
2067                         } else if (playh) {
2068                                 snprintf(fn, sizeof(fn), "digits/hundred");
2069                                 playh = 0;
2070                         } else  if (num < 10) {
2071                                 snprintf(fn, sizeof(fn), "digits/%d", num);
2072                                 num = 0;
2073                         } else  if (num < 100) {
2074                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2075                                 num -= ((num / 10) * 10);
2076                         } else {
2077                                 if (num < 1000){
2078                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2079                                         playh++;
2080                                         num -= ((num / 100) * 100);
2081                                 } else {
2082                                         if (num < 1000000) { /* 1,000,000 */
2083                                                 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
2084                                                 if (res)
2085                                                         return res;
2086                                                 num = num % 1000;
2087                                                 snprintf(fn, sizeof(fn), "digits/thousand");
2088                                         } else {
2089                                                 if (num < 1000000000) { /* 1,000,000,000 */
2090                                                         res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2091                                                         if (res)
2092                                                                 return res;
2093                                                         num = num % 1000000;
2094                                                         snprintf(fn, sizeof(fn), "digits/million");
2095                                                 } else {
2096                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2097                                                         res = -1;
2098                                                 }
2099                                         }
2100                                 }
2101                         }
2102                         if (!res) {
2103                                 if(!ast_streamfile(chan, fn, language)) {
2104                                         if ((audiofd > -1) && (ctrlfd > -1))
2105                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2106                                         else
2107                                                 res = ast_waitstream(chan, ints);
2108                                 }
2109                                 ast_stopstream(chan);
2110                         }
2111         }
2112         return res;
2113 }
2114
2115 /*--- ast_say_enumeration_full: call language-specific functions */
2116 /* Called from AGI */
2117 int ast_say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2118 {
2119         if (!strcasecmp(language,"en") ) {      /* English syntax */
2120            return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2121         } else if (!strcasecmp(language, "de") ) {      /* German syntax */
2122            return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2123         } 
2124         
2125         /* Default to english */
2126         return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2127 }
2128
2129 /*--- ast_say_enumeration: call language-specific functions without file descriptors */
2130 int ast_say_enumeration(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options)
2131 {
2132         return(ast_say_enumeration_full(chan, num, ints, language, options, -1, -1));
2133 }
2134
2135 /*--- ast_say_enumeration_full_en: English syntax */
2136 /* This is the default syntax, if no other syntax defined in this file is used */
2137 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2138 {
2139         int res = 0, t = 0;
2140         char fn[256] = "";
2141         
2142         while(!res && num) {
2143                 if (num < 0) {
2144                         snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2145                         if ( num > INT_MIN ) {
2146                                 num = -num;
2147                         } else {
2148                                 num = 0;
2149                         }       
2150                 } else if (num < 20) {
2151                         snprintf(fn, sizeof(fn), "digits/h-%d", num);
2152                         num = 0;
2153                 } else if (num < 100) { 
2154                         int tens = num / 10;
2155                         num = num % 10;
2156                         if (num == 0) {
2157                                 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2158                         } else {
2159                                 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2160                         }
2161                 } else if (num < 1000) {
2162                         int hundreds = num / 100;
2163                         num = num % 100;
2164                         if (hundreds > 1 || t == 1) {
2165                                 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2166                         }                       
2167                         if (res)
2168                                 return res;
2169                         if (num) {
2170                                 snprintf(fn, sizeof(fn), "digits/hundred");
2171                         } else {
2172                                 snprintf(fn, sizeof(fn), "digits/h-hundred");
2173                         }
2174                 } else if (num < 1000000) {
2175                         int thousands = num / 1000;
2176                         num = num % 1000;
2177                         if (thousands > 1 || t == 1) {
2178                                 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2179                         }
2180                         if (res)
2181                                 return res;
2182                         if (num) {                                      
2183                                 snprintf(fn, sizeof(fn), "digits/thousand");
2184                         } else {
2185                                 snprintf(fn, sizeof(fn), "digits/h-thousand");
2186                         }
2187                         t = 1;
2188                 } else if (num < 1000000000) {
2189                         int millions = num / 1000000;
2190                         num = num % 1000000;
2191                         t = 1;
2192                         res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2193                         if (res)
2194                                 return res;
2195                         if (num) {                                      
2196                                 snprintf(fn, sizeof(fn), "digits/million");
2197                         } else {
2198                                 snprintf(fn, sizeof(fn), "digits/h-million");
2199                         }
2200                 } else if (num < INT_MAX) {
2201                         int billions = num / 1000000000;
2202                         num = num % 1000000000;
2203                         t = 1;
2204                         res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2205                         if (res)
2206                                 return res;
2207                         if (num) {                                      
2208                                 snprintf(fn, sizeof(fn), "digits/billion");
2209                         } else {
2210                                 snprintf(fn, sizeof(fn), "digits/h-billion");
2211                         }
2212                 } else if (num == INT_MAX) {
2213                         snprintf(fn, sizeof(fn), "digits/h-last");
2214                         num = 0;
2215                 } else {
2216                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2217                         res = -1;
2218                 }
2219
2220                 if (!res) {
2221                         if (!ast_streamfile(chan, fn, language)) {
2222                                 if ((audiofd > -1) && (ctrlfd > -1)) {
2223                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2224                                 } else {
2225                                         res = ast_waitstream(chan, ints);
2226                                 }
2227                         }
2228                         ast_stopstream(chan);
2229                 }
2230         }
2231         return res;
2232 }
2233
2234 /*--- ast_say_enumeration_full_de: German syntax */
2235 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)
2236 {
2237         /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2238         int res = 0, t = 0;
2239         char fn[256] = "", fna[256] = "";
2240         char *gender;
2241
2242         if (options && !strncasecmp(options, "f",1)) {
2243                 gender = "F";
2244         } else if (options && !strncasecmp(options, "n",1)) {
2245                 gender = "N";
2246         } else {
2247                 gender = "";
2248         }
2249
2250         if (!num) 
2251                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
2252
2253         while(!res && num) {
2254                 if (num < 0) {
2255                         snprintf(fn, sizeof(fn), "digits/minus"); /* kind of senseless for enumerations, but our best effort for error checking */
2256                         if ( num > INT_MIN ) {
2257                                 num = -num;
2258                         } else {
2259                                 num = 0;
2260                         }       
2261                 } else if (num < 100 && t) {
2262                         snprintf(fn, sizeof(fn), "digits/and");
2263                         t = 0;
2264                 } else if (num < 20) {
2265                         snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2266                         num = 0;
2267                 } else if (num < 100) {
2268                         int ones = num % 10;
2269                         if (ones) {
2270                                 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2271                                 num -= ones;
2272                         } else {
2273                                 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2274                                 num = 0;
2275                         }
2276                 } else if (num == 100 && t == 0) {
2277                         snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2278                         num = 0;
2279                 } else if (num < 1000) {
2280                         int hundreds = num / 100;
2281                         num = num % 100;
2282                         if (hundreds == 1) {
2283                                 snprintf(fn, sizeof(fn), "digits/1N");
2284                         } else {
2285                                 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2286                         }
2287                         if (num) {                                      
2288                                 snprintf(fna, sizeof(fna), "digits/hundred");
2289                         } else {
2290                                 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2291                         }
2292                         t = 1;
2293                 } else  if (num < 1000000) {
2294                         int thousands = num / 1000;
2295                         num = num % 1000;
2296                         if (thousands == 1) {
2297                                 if (num) {                                      
2298                                         snprintf(fn, sizeof(fn), "digits/1N");
2299                                         snprintf(fna, sizeof(fna), "digits/thousand");
2300                                 } else {
2301                                         if (t) {
2302                                                 snprintf(fn, sizeof(fn), "digits/1N");
2303                                                 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2304                                         } else {
2305                                                 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2306                                         }
2307                                 }
2308                         } else {
2309                                 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2310                                 if (res) {
2311                                         return res;
2312                                 }
2313                                 if (num) {                                      
2314                                         snprintf(fn, sizeof(fn), "digits/thousand");
2315                                 } else {
2316                                         snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2317                                 }
2318                         }
2319                         t = 1;
2320                 } else if (num < 1000000000) {
2321                         int millions = num / 1000000;
2322                         num = num % 1000000;
2323                         if (millions == 1) {
2324                                 if (num) {                                      
2325                                         snprintf(fn, sizeof(fn), "digits/1F");
2326                                         snprintf(fna, sizeof(fna), "digits/million");
2327                                 } else {
2328                                         snprintf(fn, sizeof(fn), "digits/1N");
2329                                         snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2330                                 }
2331                         } else {
2332                                 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2333                                 if (res) {
2334                                         return res;
2335                                 }
2336                                 if (num) {                                      
2337                                         snprintf(fn, sizeof(fn), "digits/millions");
2338                                 } else {
2339                                         snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2340                                 }
2341                         }
2342                         t = 1;
2343                 } else if (num < INT_MAX) {
2344                         int billions = num / 1000000000;
2345                         num = num % 1000000000;
2346                         if (billions == 1) {
2347                                 if (num) {                                      
2348                                         snprintf(fn, sizeof(fn), "digits/1F");
2349                                         snprintf(fna, sizeof(fna), "digits/milliard");
2350                                 } else {
2351                                         snprintf(fn, sizeof(fn), "digits/1N");
2352                                         snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2353                                 }
2354                         } else {
2355                                 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2356                                 if (res)
2357                                         return res;
2358                                 if (num) {                                      
2359                                         snprintf(fn, sizeof(fna), "digits/milliards");
2360                                 } else {
2361                                         snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2362                                 }
2363                         }
2364                         t = 1;
2365                 } else if (num == INT_MAX) {
2366                         snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2367                         num = 0;
2368                 } else {
2369                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
2370                         res = -1;
2371                 }
2372
2373                 if (!res) {
2374                         if (!ast_streamfile(chan, fn, language)) {
2375                                 if ((audiofd > -1) && (ctrlfd > -1)) 
2376                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2377                                 else  
2378                                         res = ast_waitstream(chan, ints);
2379                         }
2380                         ast_stopstream(chan);
2381                         if (!res) {
2382                                 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2383                                         if ((audiofd > -1) && (ctrlfd > -1)) {
2384                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2385                                         } else {
2386                                                 res = ast_waitstream(chan, ints);
2387                                         }
2388                                 }
2389                                 ast_stopstream(chan);
2390                                 strcpy(fna, "");
2391                         }
2392                 }
2393         }
2394         return res;
2395 }
2396
2397 int ast_say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2398 {
2399         if (!strcasecmp(lang, "en") ) { /* English syntax */
2400                 return(ast_say_date_en(chan, t, ints, lang));
2401         } else if (!strcasecmp(lang, "de") ) {  /* German syntax */
2402                 return(ast_say_date_de(chan, t, ints, lang));
2403         } else if (!strcasecmp(lang, "fr") ) {  /* French syntax */
2404                 return(ast_say_date_fr(chan, t, ints, lang));
2405         } else if (!strcasecmp(lang, "nl") ) {  /* Dutch syntax */
2406                 return(ast_say_date_nl(chan, t, ints, lang));
2407         } else if (!strcasecmp(lang, "pt") ) {  /* Portuguese syntax */
2408                 return(ast_say_date_pt(chan, t, ints, lang));
2409         } else if (!strcasecmp(lang, "gr") ) {                          /* Greek syntax */
2410                 return(ast_say_date_gr(chan, t, ints, lang));
2411         }
2412
2413         /* Default to English */
2414         return(ast_say_date_en(chan, t, ints, lang));
2415 }
2416
2417 /* English syntax */
2418 int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2419 {
2420         struct tm tm;
2421         char fn[256];
2422         int res = 0;
2423         ast_localtime(&t,&tm,NULL);
2424         if (!res) {
2425                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2426                 res = ast_streamfile(chan, fn, lang);
2427                 if (!res)
2428                         res = ast_waitstream(chan, ints);
2429         }
2430         if (!res) {
2431                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2432                 res = ast_streamfile(chan, fn, lang);
2433                 if (!res)
2434                         res = ast_waitstream(chan, ints);
2435         }
2436         if (!res)
2437                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2438         if (!res)
2439                 res = ast_waitstream(chan, ints);
2440         if (!res)
2441                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2442         return res;
2443 }
2444
2445 /* German syntax */
2446 int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2447 {
2448         struct tm tm;
2449         char fn[256];
2450         int res = 0;
2451         ast_localtime(&t,&tm,NULL);
2452         if (!res) {
2453                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2454                 res = ast_streamfile(chan, fn, lang);
2455                 if (!res)
2456                         res = ast_waitstream(chan, ints);
2457         }
2458         if (!res)
2459                 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2460         if (!res)
2461                 res = ast_waitstream(chan, ints);
2462         if (!res) {
2463                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2464                 res = ast_streamfile(chan, fn, lang);
2465                 if (!res)
2466                         res = ast_waitstream(chan, ints);
2467         }
2468         if (!res) {
2469                 /* Year */
2470                 int year = tm.tm_year + 1900;
2471                 if (year > 1999) {      /* year 2000 and later */
2472                         res = ast_say_number(chan, year, ints, lang, (char *) NULL);    
2473                 } else {
2474                         if (year < 1100) {
2475                                 /* I'm not going to handle 1100 and prior */
2476                                 /* We'll just be silent on the year, instead of bombing out. */
2477                         } else {
2478                             /* year 1100 to 1999. will anybody need this?!? */
2479                             /* say 1967 as 'neunzen hundert sieben und sechzig' */
2480                                 snprintf(fn,sizeof(fn), "digits/%d", (year / 100) );
2481                                 res = wait_file(chan, ints, fn, lang);
2482                                 if (!res) {
2483                                         res = wait_file(chan,ints, "digits/hundred", lang);
2484                                         if (!res && year % 100 != 0) {
2485                                                 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);    
2486                                         }
2487                                 }
2488                         }
2489                 }
2490         }
2491         return res;
2492 }
2493
2494 /* French syntax */
2495 int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2496 {
2497         struct tm tm;
2498         char fn[256];
2499         int res = 0;
2500         ast_localtime(&t,&tm,NULL);
2501         if (!res) {
2502                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2503                 res = ast_streamfile(chan, fn, lang);
2504                 if (!res)
2505                         res = ast_waitstream(chan, ints);
2506         }
2507         if (!res)
2508                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2509         if (!res)
2510                 res = ast_waitstream(chan, ints);
2511         if (!res) {
2512                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2513                 res = ast_streamfile(chan, fn, lang);
2514                 if (!res)
2515                         res = ast_waitstream(chan, ints);
2516         }
2517         if (!res)
2518                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2519         return res;
2520 }
2521
2522 /* Dutch syntax */
2523 int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2524 {
2525         struct tm tm;
2526         char fn[256];
2527         int res = 0;
2528         ast_localtime(&t,&tm,NULL);
2529         if (!res) {
2530                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2531                 res = ast_streamfile(chan, fn, lang);
2532                 if (!res)
2533                         res = ast_waitstream(chan, ints);
2534         }
2535         if (!res)
2536                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2537         if (!res) {
2538                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2539                 res = ast_streamfile(chan, fn, lang);
2540                 if (!res)
2541                         res = ast_waitstream(chan, ints);
2542         }
2543         if (!res)
2544                 res = ast_waitstream(chan, ints);
2545         if (!res)
2546                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2547         return res;
2548 }
2549
2550 /* Portuguese syntax */
2551 int ast_say_date_pt(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2552 {
2553         struct tm tm;
2554         char fn[256];
2555         int res = 0;
2556         ast_localtime(&t,&tm,NULL);
2557         localtime_r(&t,&tm);
2558         snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2559         if (!res)
2560                 res = wait_file(chan, ints, fn, lang);
2561         if (!res)
2562                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
2563         if (!res)
2564                 res = wait_file(chan, ints, "digits/pt-de", lang);
2565         snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2566         if (!res)
2567                 res = wait_file(chan, ints, fn, lang);
2568         if (!res)
2569                 res = wait_file(chan, ints, "digits/pt-de", lang);
2570         if (!res)
2571                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2572
2573         return res;
2574 }
2575
2576 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)
2577 {
2578         if (!strcasecmp(lang, "en") ) { /* English syntax */
2579                 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2580         } else if (!strcasecmp(lang, "de") ) {  /* German syntax */
2581                 return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone));
2582         } else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) {        /* Spanish syntax */
2583                 return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone));
2584         } else if (!strcasecmp(lang, "fr") ) {  /* French syntax */
2585                 return(ast_say_date_with_format_fr(chan, time, ints, lang, format, timezone));
2586         } else if (!strcasecmp(lang, "it") ) {  /* Italian syntax */
2587                 return(ast_say_date_with_format_it(chan, time, ints, lang, format, timezone));
2588         } else if (!strcasecmp(lang, "nl") ) {  /* Dutch syntax */
2589                 return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone));
2590         } else if (!strcasecmp(lang, "pt") ) {  /* Portuguese syntax */
2591                 return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone));
2592         } else if (!strcasecmp(lang, "tw") ) {  /* Taiwanese syntax */
2593                 return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone));
2594         } else if (!strcasecmp(lang, "gr") ) {                          /* Greek syntax */
2595                 return(ast_say_date_with_format_gr(chan, time, ints, lang, format, timezone));
2596         }
2597
2598         /* Default to English */
2599         return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
2600 }
2601
2602 /* English syntax */
2603 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)
2604 {
2605         struct tm tm;
2606         int res=0, offset, sndoffset;
2607         char sndfile[256], nextmsg[256];
2608
2609         ast_localtime(&time,&tm,timezone);
2610
2611         for (offset=0 ; format[offset] != '\0' ; offset++) {
2612                 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
2613                 switch (format[offset]) {
2614                         /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
2615                         case '\'':
2616                                 /* Literal name of a sound file */
2617                                 sndoffset=0;
2618                                 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
2619                                         sndfile[sndoffset] = format[offset];
2620                                 sndfile[sndoffset] = '\0';
2621                                 res = wait_file(chan,ints,sndfile,lang);
2622                                 break;
2623                         case 'A':
2624                         case 'a':
2625                                 /* Sunday - Saturday */
2626                                 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
2627                                 res = wait_file(chan,ints,nextmsg,lang);
2628                                 break;
2629                         case 'B':
2630                         case 'b':
2631                         case 'h':
2632                                 /* January - December */
2633                                 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
2634                                 res = wait_file(chan,ints,nextmsg,lang);
2635                                 break;
2636                         case 'm':
2637                                 /* Month enumerated */
2638                                 res = ast_say_enumeration(chan, (tm.tm_mon + 1), ints, lang, (char *) NULL);    
2639                                 break;
2640                         case 'd':
2641                         case 'e':
2642                                 /* First - Thirtyfirst */
2643                                 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char *) NULL); 
2644                                 break;
2645                         case 'Y':
2646                                 /* Year */
2647                                 if (tm.tm_year > 99) {
2648                                         res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2649                                 } else {
2650                                         if (tm.tm_year < 1) {
2651                                                 /* I'm not going to handle 1900 and prior */
2652                                                 /* We'll just be silent on the year, instead of bombing out. */
2653                                         } else {
2654                                                 res = wait_file(chan,ints, "digits/19",lang);
2655                                                 if (!res) {
2656                                                         if (tm.tm_year <= 9) {
2657                                                                 /* 1901 - 1909 */
2658                                                                 res = wait_file(chan,ints, "digits/oh",lang);
2659                                                                 if (!res) {
2660                                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2661                                                                         res = wait_file(chan,ints,nextmsg,lang);
2662                                                                 }
2663                                                         } else if (tm.tm_year <= 20) {
2664                                                                 /* 1910 - 1920 */
2665                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2666                                                                 res = wait_file(chan,ints,nextmsg,lang);
2667                                                         } else {
2668                                                                 /* 1921 - 1999 */
2669                                                                 int ten, one;
2670                                                                 ten = tm.tm_year / 10;
2671                                                                 one = tm.tm_year % 10;
2672                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
2673                                                                 res = wait_file(chan,ints,nextmsg,lang);
2674                                                                 if (!res) {
2675                                                                         if (one != 0) {
2676                                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2677                                                                                 res = wait_file(chan,ints,nextmsg,lang);
2678                                                                         }
2679                                                                 }
2680                                                         }
2681                                                 }
2682                                         }
2683                                 }
2684                                 break;
2685                         case 'I':
2686                         case 'l':
2687                                 /* 12-Hour */
2688                                 if (tm.tm_hour == 0)
2689                                         snprintf(nextmsg,sizeof(nextmsg), "digits/12");
2690                                 else if (tm.tm_hour > 12)
2691                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
2692                                 else
2693                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
2694                                 res = wait_file(chan,ints,nextmsg,lang);
2695                                 break;
2696                         case 'H':
2697                         case 'k':
2698                                 /* 24-Hour */
2699                                 if (format[offset] == 'H') {
2700                                         /* e.g. oh-eight */
2701                                         if (tm.tm_hour < 10) {
2702                                                 res = wait_file(chan,ints, "digits/oh",lang);
2703                                         }
2704                                 } else {
2705                                         /* e.g. eight */
2706                                         if (tm.tm_hour == 0) {
2707                                                 res = wait_file(chan,ints, "digits/oh",lang);
2708                                         }
2709                                 }
2710                                 if (!res) {
2711                                         if (tm.tm_hour != 0) {
2712                                                 int remainder = tm.tm_hour;
2713                                                 if (tm.tm_hour > 20) {
2714                                                         res = wait_file(chan,ints, "digits/20",lang);
2715                                                         remainder -= 20;
2716                                                 }
2717                                                 if (!res) {
2718                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
2719                                                         res = wait_file(chan,ints,nextmsg,lang);
2720                                                 }
2721                                         }
2722                                 }
2723                                 break;
2724                         case 'M':
2725                                 /* Minute */
2726                                 if (tm.tm_min == 0) {
2727                                         res = wait_file(chan,ints, "digits/oclock",lang);
2728                                 } else if (tm.tm_min < 10) {
2729                                         res = wait_file(chan,ints, "digits/oh",lang);
2730                                         if (!res) {
2731                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2732                                                 res = wait_file(chan,ints,nextmsg,lang);
2733                                         }
2734                                 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
2735                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2736                                         res = wait_file(chan,ints,nextmsg,lang);
2737                                 } else {
2738                                         int ten, one;
2739                                         ten = (tm.tm_min / 10) * 10;
2740                                         one = (tm.tm_min % 10);
2741                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2742                                         res = wait_file(chan,ints,nextmsg,lang);
2743                                         if (!res) {
2744                                                 /* Fifty, not fifty-zero */
2745                                                 if (one != 0) {
2746                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2747                                                         res = wait_file(chan,ints,nextmsg,lang);
2748                                                 }
2749                                         }
2750                                 }
2751                                 break;
2752                         case 'P':
2753                         case 'p':
2754                                 /* AM/PM */
2755                                 if (tm.tm_hour > 11)
2756                                         snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
2757                                 else
2758                                         snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");