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