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