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