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