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