Update chanelog
[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 static int exp10_int(int power)
1198 {
1199         int x, res= 1;
1200         for (x=0;x<power;x++)
1201                 res *= 10;
1202         return res;
1203 }
1204
1205 typedef struct {  
1206         char *separator_dziesiatek;
1207         char *cyfry[10];
1208         char *cyfry2[10];
1209         char *setki[10];
1210         char *dziesiatki[10];
1211         char *nastki[10];  
1212         char *rzedy[3][3];
1213 } odmiana;
1214
1215 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1216 {
1217         if (rzad==0)
1218                 return "";
1219  
1220         if (i==1)
1221                 return odm->rzedy[rzad - 1][0];
1222         if ((i > 21 || i < 11) &&  i%10 > 1 && i%10 < 5)
1223                 return odm->rzedy[rzad - 1][1];
1224         else
1225                 return odm->rzedy[rzad - 1][2];
1226 }
1227
1228 static char* pl_append(char* buffer, char* str)
1229 {
1230         strcpy(buffer, str);
1231         buffer += strlen(str); 
1232         return buffer;
1233 }
1234
1235 static void pl_odtworz_plik(struct ast_channel *chan, char *language, int audiofd, int ctrlfd, char *ints, char *fn)
1236 {    
1237         char file_name[255] = "digits/";
1238         strcat(file_name, fn);
1239         ast_log(LOG_DEBUG, "Trying to play: %s\n", file_name);
1240         if (!ast_streamfile(chan, file_name, language)) {
1241                 if (audiofd && ctrlfd)
1242                         ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1243                 else
1244                         ast_waitstream(chan, ints);
1245         }
1246         ast_stopstream(chan);
1247 }
1248
1249 static void powiedz(struct ast_channel *chan, char *language, int audiofd, int ctrlfd, char *ints, odmiana *odm, int rzad, int i)
1250 {
1251         /* Initialise variables to allow compilation on Debian-stable, etc */
1252         int m1000E6 = 0;
1253         int i1000E6 = 0;
1254         int m1000E3 = 0;
1255         int i1000E3 = 0;
1256         int m1000 = 0;
1257         int i1000 = 0;
1258         int m100 = 0;
1259         int i100 = 0;
1260         
1261         if (i == 0 && rzad > 0) { 
1262                 return;
1263         }
1264         if (i == 0) {
1265                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1266         }
1267
1268         m1000E6 = i % 1000000000;
1269         i1000E6 = i / 1000000000;
1270
1271         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1272
1273         m1000E3 = m1000E6 % 1000000;
1274         i1000E3 = m1000E6 / 1000000;
1275
1276         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1277
1278         m1000 = m1000E3 % 1000;
1279         i1000 = m1000E3 / 1000;
1280
1281         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1282
1283         m100 = m1000 % 100;
1284         i100 = m1000 / 100;
1285         
1286         if (i100>0)
1287                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1288
1289         if ( m100 > 0 && m100 <=9 ) {
1290                 if (m1000>0)
1291                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1292                 else
1293                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1294         } else if (m100 % 10 == 0) {
1295                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1296         } else if (m100 <= 19 ) {
1297                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1298         } else if (m100 != 0) {
1299                 if (odm->separator_dziesiatek[0]==' ') {
1300                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1301                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1302                 } else {
1303                         char buf[10];
1304                         char *b = buf;
1305                         b = pl_append(b, odm->dziesiatki[m100 / 10]);  
1306                         b = pl_append(b, odm->separator_dziesiatek);  
1307                         b = pl_append(b, odm->cyfry2[m100 % 10]); 
1308                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1309                 }
1310         } 
1311
1312         if (rzad > 0) {
1313                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1314         }
1315 }
1316
1317 /* ast_say_number_full_pl: Polish syntax */
1318 static int ast_say_number_full_pl(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
1319 /*
1320 Sounds needed:
1321 0               zero
1322 1               jeden
1323 10              dziesiec
1324 100             sto
1325 1000            tysiac
1326 1000000         milion
1327 1000000000      miliard
1328 1000000000.2    miliardy
1329 1000000000.5    miliardow
1330 1000000.2       miliony
1331 1000000.5       milionow
1332 1000.2          tysiace
1333 1000.5          tysiecy
1334 100m            stu
1335 10m             dziesieciu
1336 11              jedenascie
1337 11m             jedenastu
1338 12              dwanascie
1339 12m             dwunastu
1340 13              trzynascie
1341 13m             trzynastu
1342 14              czternascie
1343 14m             czternastu
1344 15              pietnascie
1345 15m             pietnastu
1346 16              szesnascie
1347 16m             szesnastu
1348 17              siedemnascie
1349 17m             siedemnastu
1350 18              osiemnascie
1351 18m             osiemnastu
1352 19              dziewietnascie
1353 19m             dziewietnastu
1354 1z              jedna
1355 2               dwie
1356 20              dwadziescia
1357 200             dwiescie
1358 200m            dwustu
1359 20m             dwudziestu
1360 2-1m            dwaj
1361 2-2m            dwoch
1362 2z              dwie
1363 3               trzy
1364 30              trzydziesci
1365 300             trzysta
1366 300m            trzystu
1367 30m             trzydziestu
1368 3-1m            trzej
1369 3-2m            trzech
1370 4               cztery
1371 40              czterdziesci
1372 400             czterysta
1373 400m            czterystu
1374 40m             czterdziestu
1375 4-1m            czterej
1376 4-2m            czterech
1377 5               piec
1378 50              piecdziesiat
1379 500             piecset
1380 500m            pieciuset
1381 50m             piedziesieciu
1382 5m              pieciu
1383 6               szesc
1384 60              szescdziesiat
1385 600             szescset
1386 600m            szesciuset
1387 60m             szescdziesieciu
1388 6m              szesciu
1389 7               siedem
1390 70              siedemdziesiat
1391 700             siedemset
1392 700m            siedmiuset
1393 70m             siedemdziesieciu
1394 7m              siedmiu
1395 8               osiem
1396 80              osiemdziesiat
1397 800             osiemset
1398 800m            osmiuset
1399 80m             osiemdziesieciu
1400 8m              osmiu
1401 9               dziewiec
1402 90              dziewiecdziesiat
1403 900             dziewiecset
1404 900m            dziewieciuset
1405 90m             dziewiedziesieciu
1406 9m              dziewieciu
1407 and combinations of eg.: 20_1, 30m_3m, etc...
1408
1409 */
1410 {
1411         char *zenski_cyfry[] = {"0","1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1412
1413         char *zenski_cyfry2[] = {"0","1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1414
1415         char *meski_cyfry[] = {"0","1", "2-1m", "3-1m", "4-1m", "5m",  /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1416
1417         char *meski_cyfry2[] = {"0","1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1418
1419         char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1420
1421         char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1422
1423         char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1424
1425         char *nijaki_cyfry[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1426
1427         char *nijaki_cyfry2[] = {"0","1", "2", "3", "4", "5", "6", "7", "8", "9"};
1428
1429         char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1430
1431         char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1432
1433         char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1434
1435         char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 
1436
1437         /* Initialise variables to allow compilation on Debian-stable, etc */
1438         odmiana *o;
1439
1440         static odmiana *odmiana_nieosobowa = NULL; 
1441         static odmiana *odmiana_meska = NULL; 
1442         static odmiana *odmiana_zenska = NULL; 
1443
1444         if (odmiana_nieosobowa == NULL) {
1445                 odmiana_nieosobowa = (odmiana *) malloc(sizeof(odmiana));
1446
1447                 odmiana_nieosobowa->separator_dziesiatek = "_";
1448
1449                 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1450                 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1451                 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1452                 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1453                 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1454                 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1455         }
1456
1457         if (odmiana_zenska == NULL) {
1458                 odmiana_zenska = (odmiana *) malloc(sizeof(odmiana));
1459
1460                 odmiana_zenska->separator_dziesiatek = " ";
1461
1462                 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
1463                 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
1464                 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
1465                 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
1466                 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
1467                 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
1468         }
1469
1470         if (odmiana_meska == NULL) {
1471                 odmiana_meska = (odmiana *) malloc(sizeof(odmiana));
1472
1473                 odmiana_meska->separator_dziesiatek = " ";
1474
1475                 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
1476                 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
1477                 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
1478                 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
1479                 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
1480                 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
1481         }
1482
1483         if (options) {
1484                 if (strncasecmp(options, "f", 1) == 0)
1485                         o = odmiana_zenska;
1486                 else if (strncasecmp(options, "m", 1) == 0)
1487                         o = odmiana_meska;
1488                 else
1489                         o = odmiana_nieosobowa;
1490         } else
1491                 o = odmiana_nieosobowa;
1492
1493         powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
1494         return 0;
1495 }
1496
1497 /* ast_say_number_full_pt: Portuguese syntax */
1498 /*      Extra sounds needed: */
1499 /*      For feminin all sound files end with F */
1500 /*      100E for 100+ something */
1501 /*      1000000S for plural */
1502 /*      pt-e for 'and' */
1503 static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
1504 {
1505         int res = 0;
1506         int playh = 0;
1507         int mf = 1;                            /* +1 = Masculin; -1 = Feminin */
1508         char fn[256] = "";
1509
1510         if (!num) 
1511                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1512
1513         if (options && !strncasecmp(options, "f",1))
1514                 mf = -1;
1515
1516         while(!res && num ) {
1517                 if (num < 20) {
1518                         if ((num == 1 || num == 2) && (mf < 0))
1519                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
1520                         else
1521                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1522                         num = 0;
1523                 } else if (num < 100) {
1524                         snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
1525                         if (num % 10)
1526                                 playh = 1;
1527                         num = num % 10;
1528                 } else if (num < 1000) {
1529                         if (num == 100)
1530                                 snprintf(fn, sizeof(fn), "digits/100");
1531                         else if (num < 200)
1532                                 snprintf(fn, sizeof(fn), "digits/100E");
1533                         else {
1534                                 if (mf < 0 && num > 199)
1535                                         snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
1536                                 else
1537                                         snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
1538                                 if (num % 100)
1539                                         playh = 1;
1540                         }
1541                         num = num % 100;
1542                 } else if (num < 1000000) {
1543                         if (num > 1999) {
1544                                 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
1545                                 if (res)
1546                                         return res;
1547                         }
1548                         snprintf(fn, sizeof(fn), "digits/1000");
1549                         if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
1550                                 playh = 1;
1551                         num = num % 1000;
1552                 } else if (num < 1000000000) {
1553                         res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
1554                         if (res)
1555                                 return res;
1556                         if (num < 2000000)
1557                                 snprintf(fn, sizeof(fn), "digits/1000000");
1558                         else
1559                                 snprintf(fn, sizeof(fn), "digits/1000000S");
1560  
1561                         if ((num % 1000000) &&
1562                                 // no thousands
1563                                 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
1564                                 // no hundreds and below
1565                                 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
1566                                 playh = 1;
1567                         num = num % 1000000;
1568                 }
1569                 if (!res && playh) {
1570                         res = wait_file(chan, ints, "digits/pt-e", language);
1571                         ast_stopstream(chan);
1572                         playh = 0;
1573                 }
1574                 if (!res) {
1575                         if(!ast_streamfile(chan, fn, language)) {
1576                                 if (audiofd && ctrlfd)
1577                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);                 else
1578                                         res = ast_waitstream(chan, ints);
1579                         }
1580                         ast_stopstream(chan);
1581                 }
1582         }
1583         return res;
1584 }
1585
1586 /*--- ast_say_number_full_se: Swedish/Norwegian syntax */
1587 static int ast_say_number_full_se(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
1588 {
1589         int res = 0;
1590         int playh = 0;
1591         char fn[256] = "";
1592         int cn = 1;             /* +1 = Commune; -1 = Neutrum */
1593         if (!num) 
1594                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1595         if (options && !strncasecmp(options, "n",1)) cn = -1;
1596
1597         while(!res && (num || playh)) {
1598                         if (playh) {
1599                                 snprintf(fn, sizeof(fn), "digits/hundred");
1600                                 playh = 0;
1601                         } else
1602                         if (num < 20) {
1603                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1604                                 num = 0;
1605                         } else
1606                         if (num < 100) {
1607                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1608                                 num -= ((num / 10) * 10);
1609                         } else 
1610                         if (num == 1 && cn == -1) {     /* En eller ett? */
1611                                 snprintf(fn, sizeof(fn), "digits/1N");
1612                                 num = 0;
1613                         } else {
1614                                 if (num < 1000){
1615                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1616                                         playh++;
1617                                         num -= ((num / 100) * 100);
1618                                 } else {
1619                                         if (num < 1000000) { /* 1,000,000 */
1620                                                 res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1621                                                 if (res)
1622                                                         return res;
1623                                                 num = num % 1000;
1624                                                 snprintf(fn, sizeof(fn), "digits/thousand");
1625                                         } else {
1626                                                 if (num < 1000000000) { /* 1,000,000,000 */
1627                                                         res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1628                                                         if (res)
1629                                                                 return res;
1630                                                         num = num % 1000000;
1631                                                         snprintf(fn, sizeof(fn), "digits/million");
1632                                                 } else {
1633                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1634                                                         res = -1;
1635                                                 }
1636                                         }
1637                                 }
1638                         }
1639                          if (!res) {
1640                                 if(!ast_streamfile(chan, fn, language)) {
1641                                     if (audiofd && ctrlfd)
1642                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1643                                     else
1644                                          res = ast_waitstream(chan, ints);
1645                                 }
1646                                 ast_stopstream(chan);
1647
1648                         }
1649                         
1650         }
1651         return res;
1652 }
1653
1654
1655 /*--- ast_say_number_full_tw: Taiwanese syntax */
1656 static int ast_say_number_full_tw(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
1657 {
1658         int res = 0;
1659         int playh = 0;
1660         char fn[256] = "";
1661         if (!num)
1662                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1663
1664         while(!res && (num || playh)) {
1665                 if (playh) {
1666                                 snprintf(fn, sizeof(fn), "digits/hundred");
1667                                 playh = 0;
1668                         } else  if (num < 10) {
1669                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1670                                 num = 0;
1671                         } else  if (num < 100) {
1672                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1673                                 num -= ((num / 10) * 10);
1674                         } else {
1675                                 if (num < 1000){
1676                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1677                                         playh++;
1678                                         num -= ((num / 100) * 100);
1679                                 } else {
1680                                         if (num < 1000000) { /* 1,000,000 */
1681                                                 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
1682                                                 if (res)
1683                                                         return res;
1684                                                 num = num % 1000;
1685                                                 snprintf(fn, sizeof(fn), "digits/thousand");
1686                                         } else {
1687                                                 if (num < 1000000000) { /* 1,000,000,000 */
1688                                                         res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1689                                                         if (res)
1690                                                                 return res;
1691                                                         num = num % 1000000;
1692                                                         snprintf(fn, sizeof(fn), "digits/million");
1693                                                 } else {
1694                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
1695                                                         res = -1;
1696                                                 }
1697                                         }
1698                                 }
1699                         }
1700                         if (!res) {
1701                                 if(!ast_streamfile(chan, fn, language)) {
1702                                         if (audiofd && ctrlfd)
1703                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1704                                         else
1705                                                 res = ast_waitstream(chan, ints);
1706                                 }
1707                                 ast_stopstream(chan);
1708
1709                         }
1710         }
1711         return res;
1712 }
1713
1714 /*--- ast_say_number_full_cz: Czech syntax */
1715 /* files needed:
1716  * 1m,2m - gender male
1717  * 1w,2w - gender female
1718  * 3,4,...,20
1719  * 30,40,...,90
1720  * 
1721  * hundereds - 100 - sto, 200 - 2ste, 300,400 3,4sta, 500,600,...,900 5,6,...9set 
1722  * 
1723  * for each number 10^(3n + 3) exist 3 files represented as:
1724  *              1 tousand = jeden tisic = 1_E3
1725  *              2,3,4 tousands = dva,tri,ctyri tisice = 2-3_E3
1726  *              5,6,... tousands = pet,sest,... tisic = 5_E3
1727  *
1728  *              million = _E6
1729  *              miliard = _E9
1730  *              etc...
1731  *
1732  * tousand, milion are  gender male, so 1 and 2 is 1m 2m
1733  * miliard is gender female, so 1 and 2 is 1w 2w
1734  */
1735
1736 static int ast_say_number_full_cz(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
1737 {
1738         int res = 0;
1739         int playh = 0;
1740         char fn[256] = "";
1741         
1742         int hundered = 0;
1743         int left = 0;
1744         int length = 0;
1745         
1746         /* options - w = woman, m = man, n = neutral. Defaultl is woman */
1747         if (!options)
1748                 options = "w";
1749         
1750         if (!num) 
1751                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
1752         
1753         while(!res && (num || playh)) {
1754                 if (num < 3 ) {
1755                         snprintf(fn, sizeof(fn), "digits/%d%c",num,options[0]);
1756                         playh = 0;
1757                         num = 0;
1758                 } else if (num < 20) {
1759                         snprintf(fn, sizeof(fn), "digits/%d",num);
1760                         playh = 0;
1761                         num = 0;
1762                 } else if (num < 100) {
1763                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1764                         num -= ((num / 10) * 10);
1765                 } else if (num < 1000) {
1766                         hundered = num / 100;
1767                         if ( hundered == 1 ) {
1768                                 snprintf(fn, sizeof(fn), "digits/1sto");
1769                         } else if ( hundered == 2 ) {
1770                                 snprintf(fn, sizeof(fn), "digits/2ste");
1771                         } else {
1772                                 res = ast_say_number_full_cz(chan,hundered,ints,language,options,audiofd,ctrlfd);
1773                                 if (res)
1774                                         return res;
1775                                 if ( hundered == 3 || hundered == 4) {  
1776                                         snprintf(fn, sizeof(fn), "digits/sta");
1777                                 } else if ( hundered > 4 ) {
1778                                         snprintf(fn, sizeof(fn), "digits/set");
1779                                 }
1780                         }
1781                         num -= (hundered * 100);
1782                 } else { /* num > 1000 */
1783                         length = (int)log10(num)+1;  
1784                         while ( (length % 3 ) != 1 ) {
1785                                 length--;               
1786                         }
1787                         left = num / (exp10_int(length-1));
1788                         if ( left == 2 ) {  
1789                                 switch (length-1) {
1790                                         case 9: options = "w";  /* 1,000,000,000 gender female */
1791                                                 break;
1792                                         default : options = "m"; /* others are male */
1793                                 }
1794                         }
1795                         if ( left > 1 ) { /* we dont say "one thousand" but only thousand */
1796                                 res = ast_say_number_full_cz(chan,left,ints,language,options,audiofd,ctrlfd);
1797                                 if (res) 
1798                                         return res;
1799                         }
1800                         if ( left >= 5 ) { /* >= 5 have the same declesion */
1801                                 snprintf(fn, sizeof(fn), "digits/5_E%d",length-1);      
1802                         } else if ( left >= 2 && left <= 4 ) {
1803                                 snprintf(fn, sizeof(fn), "digits/2-4_E%d",length-1);
1804                         } else { /* left == 1 */
1805                                 snprintf(fn, sizeof(fn), "digits/1_E%d",length-1);
1806                         }
1807                         num -= left * (exp10_int(length-1));
1808                 }
1809                 if (!res) {
1810                         if(!ast_streamfile(chan, fn, language)) {
1811                                 if (audiofd && ctrlfd) {
1812                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1813                                 } else {
1814                                         res = ast_waitstream(chan, ints);
1815                                 }
1816                         }
1817                         ast_stopstream(chan);
1818                 }
1819         }
1820         return res; 
1821 }
1822
1823
1824 int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
1825 {
1826         if (!strcasecmp(lang,"en") ) {  /* English syntax */
1827                 return(ast_say_date_en(chan, t, ints, lang));
1828         } else if (!strcasecmp(lang, "nl") ) {  /* Dutch syntax */
1829                 return(ast_say_date_nl(chan, t, ints, lang));
1830         } else if (!strcasecmp(lang, "pt") ) {  /* Portuguese syntax */
1831                 return(ast_say_date_pt(chan, t, ints, lang));
1832         }
1833
1834         /* Default to English */
1835         return(ast_say_date_en(chan, t, ints, lang));
1836 }
1837
1838 /* English syntax */
1839 int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang)
1840 {
1841         struct tm tm;
1842         char fn[256];
1843         int res = 0;
1844         ast_localtime(&t,&tm,NULL);
1845         if (!res) {
1846                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
1847                 res = ast_streamfile(chan, fn, lang);
1848                 if (!res)
1849                         res = ast_waitstream(chan, ints);
1850         }
1851         if (!res) {
1852                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
1853                 res = ast_streamfile(chan, fn, lang);
1854                 if (!res)
1855                         res = ast_waitstream(chan, ints);
1856         }
1857         if (!res)
1858                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
1859         if (!res)
1860                 res = ast_waitstream(chan, ints);
1861         if (!res)
1862                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
1863         return res;
1864 }
1865
1866 /* Dutch syntax */
1867 int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang)
1868 {
1869         struct tm tm;
1870         char fn[256];
1871         int res = 0;
1872         ast_localtime(&t,&tm,NULL);
1873         if (!res) {
1874                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
1875                 res = ast_streamfile(chan, fn, lang);
1876                 if (!res)
1877                         res = ast_waitstream(chan, ints);
1878         }
1879         if (!res)
1880                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
1881         if (!res) {
1882                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
1883                 res = ast_streamfile(chan, fn, lang);
1884                 if (!res)
1885                         res = ast_waitstream(chan, ints);
1886         }
1887         if (!res)
1888                 res = ast_waitstream(chan, ints);
1889         if (!res)
1890                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
1891         return res;
1892 }
1893
1894 /* Portuguese syntax */
1895 int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang)
1896 {
1897         struct tm tm;
1898         char fn[256];
1899         int res = 0;
1900         ast_localtime(&t,&tm,NULL);
1901         localtime_r(&t,&tm);
1902         snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
1903         if (!res)
1904                 res = wait_file(chan, ints, fn, lang);
1905         if (!res)
1906                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
1907         if (!res)
1908                 res = wait_file(chan, ints, "digits/pt-de", lang);
1909         snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
1910         if (!res)
1911                 res = wait_file(chan, ints, fn, lang);
1912         if (!res)
1913                 res = wait_file(chan, ints, "digits/pt-de", lang);
1914         if (!res)
1915                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
1916
1917         return res;
1918 }
1919
1920 int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
1921 {
1922         if (!strcasecmp(lang, "en") ) { /* English syntax */
1923                 return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
1924         } else if (!strcasecmp(lang, "de") ) {  /* German syntax */
1925                 return(ast_say_date_with_format_de(chan, time, ints, lang, format, timezone));
1926         } else if (!strcasecmp(lang, "es") || !strcasecmp(lang, "mx")) {        /* Spanish syntax */
1927                 return(ast_say_date_with_format_es(chan, time, ints, lang, format, timezone));
1928         } else if (!strcasecmp(lang, "nl") ) {  /* Dutch syntax */
1929                 return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone));
1930         } else if (!strcasecmp(lang, "pt") ) {  /* Portuguese syntax */
1931                 return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone));
1932         } else if (!strcasecmp(lang, "tw") ) {  /* Taiwanese syntax */
1933                 return(ast_say_date_with_format_tw(chan, time, ints, lang, format, timezone));
1934         }
1935
1936         /* Default to English */
1937         return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
1938 }
1939
1940 /* English syntax */
1941 int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
1942 {
1943         struct tm tm;
1944         int res=0, offset, sndoffset;
1945         char sndfile[256], nextmsg[256];
1946
1947         ast_localtime(&time,&tm,timezone);
1948
1949         for (offset=0 ; format[offset] != '\0' ; offset++) {
1950                 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
1951                 switch (format[offset]) {
1952                         /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
1953                         case '\'':
1954                                 /* Literal name of a sound file */
1955                                 sndoffset=0;
1956                                 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
1957                                         sndfile[sndoffset] = format[offset];
1958                                 sndfile[sndoffset] = '\0';
1959                                 res = wait_file(chan,ints,sndfile,lang);
1960                                 break;
1961                         case 'A':
1962                         case 'a':
1963                                 /* Sunday - Saturday */
1964                                 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
1965                                 res = wait_file(chan,ints,nextmsg,lang);
1966                                 break;
1967                         case 'B':
1968                         case 'b':
1969                         case 'h':
1970                                 /* January - December */
1971                                 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
1972                                 res = wait_file(chan,ints,nextmsg,lang);
1973                                 break;
1974                         case 'd':
1975                         case 'e':
1976                                 /* First - Thirtyfirst */
1977                                 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) {
1978                                         snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday);
1979                                         res = wait_file(chan,ints,nextmsg,lang);
1980                                 } else if (tm.tm_mday == 31) {
1981                                         /* "Thirty" and "first" */
1982                                         res = wait_file(chan,ints, "digits/30",lang);
1983                                         if (!res) {
1984                                                 res = wait_file(chan,ints, "digits/h-1",lang);
1985                                         }
1986                                 } else {
1987                                         /* Between 21 and 29 - two sounds */
1988                                         res = wait_file(chan,ints, "digits/20",lang);
1989                                         if (!res) {
1990                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20);
1991                                                 res = wait_file(chan,ints,nextmsg,lang);
1992                                         }
1993                                 }
1994                                 break;
1995                         case 'Y':
1996                                 /* Year */
1997                                 if (tm.tm_year > 99) {
1998                                         res = wait_file(chan,ints, "digits/2",lang);
1999                                         if (!res) {
2000                                                 res = wait_file(chan,ints, "digits/thousand",lang);
2001                                         }
2002                                         if (tm.tm_year > 100) {
2003                                                 if (!res) {
2004                                                         /* This works until the end of 2020 */
2005                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
2006                                                         res = wait_file(chan,ints,nextmsg,lang);
2007                                                 }
2008                                         }
2009                                 } else {
2010                                         if (tm.tm_year < 1) {
2011                                                 /* I'm not going to handle 1900 and prior */
2012                                                 /* We'll just be silent on the year, instead of bombing out. */
2013                                         } else {
2014                                                 res = wait_file(chan,ints, "digits/19",lang);
2015                                                 if (!res) {
2016                                                         if (tm.tm_year <= 9) {
2017                                                                 /* 1901 - 1909 */
2018                                                                 res = wait_file(chan,ints, "digits/oh",lang);
2019                                                                 if (!res) {
2020                                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2021                                                                         res = wait_file(chan,ints,nextmsg,lang);
2022                                                                 }
2023                                                         } else if (tm.tm_year <= 20) {
2024                                                                 /* 1910 - 1920 */
2025                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2026                                                                 res = wait_file(chan,ints,nextmsg,lang);
2027                                                         } else {
2028                                                                 /* 1921 - 1999 */
2029                                                                 int ten, one;
2030                                                                 ten = tm.tm_year / 10;
2031                                                                 one = tm.tm_year % 10;
2032                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
2033                                                                 res = wait_file(chan,ints,nextmsg,lang);
2034                                                                 if (!res) {
2035                                                                         if (one != 0) {
2036                                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2037                                                                                 res = wait_file(chan,ints,nextmsg,lang);
2038                                                                         }
2039                                                                 }
2040                                                         }
2041                                                 }
2042                                         }
2043                                 }
2044                                 break;
2045                         case 'I':
2046                         case 'l':
2047                                 /* 12-Hour */
2048                                 if (tm.tm_hour == 0)
2049                                         snprintf(nextmsg,sizeof(nextmsg), "digits/12");
2050                                 else if (tm.tm_hour > 12)
2051                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
2052                                 else
2053                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
2054                                 res = wait_file(chan,ints,nextmsg,lang);
2055                                 break;
2056                         case 'H':
2057                         case 'k':
2058                                 /* 24-Hour */
2059                                 if (format[offset] == 'H') {
2060                                         /* e.g. oh-eight */
2061                                         if (tm.tm_hour < 10) {
2062                                                 res = wait_file(chan,ints, "digits/oh",lang);
2063                                         }
2064                                 } else {
2065                                         /* e.g. eight */
2066                                         if (tm.tm_hour == 0) {
2067                                                 res = wait_file(chan,ints, "digits/oh",lang);
2068                                         }
2069                                 }
2070                                 if (!res) {
2071                                         if (tm.tm_hour != 0) {
2072                                                 int remainder = tm.tm_hour;
2073                                                 if (tm.tm_hour > 20) {
2074                                                         res = wait_file(chan,ints, "digits/20",lang);
2075                                                         remainder -= 20;
2076                                                 }
2077                                                 if (!res) {
2078                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
2079                                                         res = wait_file(chan,ints,nextmsg,lang);
2080                                                 }
2081                                         }
2082                                 }
2083                                 break;
2084                         case 'M':
2085                                 /* Minute */
2086                                 if (tm.tm_min == 0) {
2087                                         res = wait_file(chan,ints, "digits/oclock",lang);
2088                                 } else if (tm.tm_min < 10) {
2089                                         res = wait_file(chan,ints, "digits/oh",lang);
2090                                         if (!res) {
2091                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2092                                                 res = wait_file(chan,ints,nextmsg,lang);
2093                                         }
2094                                 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
2095                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2096                                         res = wait_file(chan,ints,nextmsg,lang);
2097                                 } else {
2098                                         int ten, one;
2099                                         ten = (tm.tm_min / 10) * 10;
2100                                         one = (tm.tm_min % 10);
2101                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2102                                         res = wait_file(chan,ints,nextmsg,lang);
2103                                         if (!res) {
2104                                                 /* Fifty, not fifty-zero */
2105                                                 if (one != 0) {
2106                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2107                                                         res = wait_file(chan,ints,nextmsg,lang);
2108                                                 }
2109                                         }
2110                                 }
2111                                 break;
2112                         case 'P':
2113                         case 'p':
2114                                 /* AM/PM */
2115                                 if (tm.tm_hour > 11)
2116                                         snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
2117                                 else
2118                                         snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
2119                                 res = wait_file(chan,ints,nextmsg,lang);
2120                                 break;
2121                         case 'Q':
2122                                 /* Shorthand for "Today", "Yesterday", or ABdY */
2123                                 {
2124                                         struct timeval now;
2125                                         struct tm tmnow;
2126                                         time_t beg_today;
2127
2128                                         gettimeofday(&now,NULL);
2129                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
2130                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
2131                                         /* In any case, it saves not having to do ast_mktime() */
2132                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
2133                                         if (beg_today < time) {
2134                                                 /* Today */
2135                                                 res = wait_file(chan,ints, "digits/today",lang);
2136                                         } else if (beg_today - 86400 < time) {
2137                                                 /* Yesterday */
2138                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
2139                                         } else {
2140                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
2141                                         }
2142                                 }
2143                                 break;
2144                         case 'q':
2145                                 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
2146                                 {
2147                                         struct timeval now;
2148                                         struct tm tmnow;
2149                                         time_t beg_today;
2150
2151                                         gettimeofday(&now,NULL);
2152                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
2153                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
2154                                         /* In any case, it saves not having to do ast_mktime() */
2155                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
2156                                         if (beg_today < time) {
2157                                                 /* Today */
2158                                         } else if ((beg_today - 86400) < time) {
2159                                                 /* Yesterday */
2160                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
2161                                         } else if (beg_today - 86400 * 6 < time) {
2162                                                 /* Within the last week */
2163                                                 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
2164                                         } else {
2165                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
2166                                         }
2167                                 }
2168                                 break;
2169                         case 'R':
2170                                 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
2171                                 break;
2172                         case 'S':
2173                                 /* Seconds */
2174                                 if (tm.tm_sec == 0) {
2175                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
2176                                         res = wait_file(chan,ints,nextmsg,lang);
2177                                 } else if (tm.tm_sec < 10) {
2178                                         res = wait_file(chan,ints, "digits/oh",lang);
2179                                         if (!res) {
2180                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
2181                                                 res = wait_file(chan,ints,nextmsg,lang);
2182                                         }
2183                                 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
2184                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
2185                                         res = wait_file(chan,ints,nextmsg,lang);
2186                                 } else {
2187                                         int ten, one;
2188                                         ten = (tm.tm_sec / 10) * 10;
2189                                         one = (tm.tm_sec % 10);
2190                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2191                                         res = wait_file(chan,ints,nextmsg,lang);
2192                                         if (!res) {
2193                                                 /* Fifty, not fifty-zero */
2194                                                 if (one != 0) {
2195                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2196                                                         res = wait_file(chan,ints,nextmsg,lang);
2197                                                 }
2198                                         }
2199                                 }
2200                                 break;
2201                         case 'T':
2202                                 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
2203                                 break;
2204                         case ' ':
2205                         case '  ':
2206                                 /* Just ignore spaces and tabs */
2207                                 break;
2208                         default:
2209                                 /* Unknown character */
2210                                 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
2211                 }
2212                 /* Jump out on DTMF */
2213                 if (res) {
2214                         break;
2215                 }
2216         }
2217         return res;
2218 }
2219
2220 /* German syntax */
2221 /* NB This currently is a 100% clone of the English syntax, just getting ready to make changes... */
2222 int ast_say_date_with_format_de(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
2223 {
2224         struct tm tm;
2225         int res=0, offset, sndoffset;
2226         char sndfile[256], nextmsg[256];
2227
2228         ast_localtime(&time,&tm,timezone);
2229
2230         for (offset=0 ; format[offset] != '\0' ; offset++) {
2231                 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
2232                 switch (format[offset]) {
2233                         /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
2234                         case '\'':
2235                                 /* Literal name of a sound file */
2236                                 sndoffset=0;
2237                                 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
2238                                         sndfile[sndoffset] = format[offset];
2239                                 sndfile[sndoffset] = '\0';
2240                                 res = wait_file(chan,ints,sndfile,lang);
2241                                 break;
2242                         case 'A':
2243                         case 'a':
2244                                 /* Sunday - Saturday */
2245                                 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
2246                                 res = wait_file(chan,ints,nextmsg,lang);
2247                                 break;
2248                         case 'B':
2249                         case 'b':
2250                         case 'h':
2251                                 /* January - December */
2252                                 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
2253                                 res = wait_file(chan,ints,nextmsg,lang);
2254                                 break;
2255                         case 'd':
2256                         case 'e':
2257                                 /* First - Thirtyfirst */
2258                                 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) {
2259                                         snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday);
2260                                         res = wait_file(chan,ints,nextmsg,lang);
2261                                 } else if (tm.tm_mday == 31) {
2262                                         /* "Thirty" and "first" */
2263                                         res = wait_file(chan,ints, "digits/30",lang);
2264                                         if (!res) {
2265                                                 res = wait_file(chan,ints, "digits/h-1",lang);
2266                                         }
2267                                 } else {
2268                                         /* Between 21 and 29 - two sounds */
2269                                         res = wait_file(chan,ints, "digits/20",lang);
2270                                         if (!res) {
2271                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20);
2272                                                 res = wait_file(chan,ints,nextmsg,lang);
2273                                         }
2274                                 }
2275                                 break;
2276                         case 'Y':
2277                                 /* Year */
2278                                 if (tm.tm_year > 99) {
2279                                         res = wait_file(chan,ints, "digits/2",lang);
2280                                         if (!res) {
2281                                                 res = wait_file(chan,ints, "digits/thousand",lang);
2282                                         }
2283                                         if (tm.tm_year > 100) {
2284                                                 if (!res) {
2285                                                         /* This works until the end of 2020 */
2286                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
2287                                                         res = wait_file(chan,ints,nextmsg,lang);
2288                                                 }
2289                                         }
2290                                 } else {
2291                                         if (tm.tm_year < 1) {
2292                                                 /* I'm not going to handle 1900 and prior */
2293                                                 /* We'll just be silent on the year, instead of bombing out. */
2294                                         } else {
2295                                                 res = wait_file(chan,ints, "digits/19",lang);
2296                                                 if (!res) {
2297                                                         if (tm.tm_year <= 9) {
2298                                                                 /* 1901 - 1909 */
2299                                                                 res = wait_file(chan,ints, "digits/oh",lang);
2300                                                                 if (!res) {
2301                                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2302                                                                         res = wait_file(chan,ints,nextmsg,lang);
2303                                                                 }
2304                                                         } else if (tm.tm_year <= 20) {
2305                                                                 /* 1910 - 1920 */
2306                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
2307                                                                 res = wait_file(chan,ints,nextmsg,lang);
2308                                                         } else {
2309                                                                 /* 1921 - 1999 */
2310                                                                 int ten, one;
2311                                                                 ten = tm.tm_year / 10;
2312                                                                 one = tm.tm_year % 10;
2313                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
2314                                                                 res = wait_file(chan,ints,nextmsg,lang);
2315                                                                 if (!res) {
2316                                                                         if (one != 0) {
2317                                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2318                                                                                 res = wait_file(chan,ints,nextmsg,lang);
2319                                                                         }
2320                                                                 }
2321                                                         }
2322                                                 }
2323                                         }
2324                                 }
2325                                 break;
2326                         case 'I':
2327                         case 'l':
2328                                 /* 12-Hour */
2329                                 if (tm.tm_hour == 0)
2330                                         snprintf(nextmsg,sizeof(nextmsg), "digits/12");
2331                                 else if (tm.tm_hour > 12)
2332                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
2333                                 else
2334                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
2335                                 res = wait_file(chan,ints,nextmsg,lang);
2336                                 break;
2337                         case 'H':
2338                         case 'k':
2339                                 /* 24-Hour */
2340                                 if (format[offset] == 'H') {
2341                                         /* e.g. oh-eight */
2342                                         if (tm.tm_hour < 10) {
2343                                                 res = wait_file(chan,ints, "digits/oh",lang);
2344                                         }
2345                                 } else {
2346                                         /* e.g. eight */
2347                                         if (tm.tm_hour == 0) {
2348                                                 res = wait_file(chan,ints, "digits/oh",lang);
2349                                         }
2350                                 }
2351                                 if (!res) {
2352                                         if (tm.tm_hour != 0) {
2353                                                 int remainder = tm.tm_hour;
2354                                                 if (tm.tm_hour > 20) {
2355                                                         res = wait_file(chan,ints, "digits/20",lang);
2356                                                         remainder -= 20;
2357                                                 }
2358                                                 if (!res) {
2359                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
2360                                                         res = wait_file(chan,ints,nextmsg,lang);
2361                                                 }
2362                                         }
2363                                 }
2364                                 break;
2365                         case 'M':
2366                                 /* Minute */
2367                                 if (tm.tm_min == 0) {
2368                                         res = wait_file(chan,ints, "digits/oclock",lang);
2369                                 } else if (tm.tm_min < 10) {
2370                                         res = wait_file(chan,ints, "digits/oh",lang);
2371                                         if (!res) {
2372                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2373                                                 res = wait_file(chan,ints,nextmsg,lang);
2374                                         }
2375                                 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
2376                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
2377                                         res = wait_file(chan,ints,nextmsg,lang);
2378                                 } else {
2379                                         int ten, one;
2380                                         ten = (tm.tm_min / 10) * 10;
2381                                         one = (tm.tm_min % 10);
2382                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2383                                         res = wait_file(chan,ints,nextmsg,lang);
2384                                         if (!res) {
2385                                                 /* Fifty, not fifty-zero */
2386                                                 if (one != 0) {
2387                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2388                                                         res = wait_file(chan,ints,nextmsg,lang);
2389                                                 }
2390                                         }
2391                                 }
2392                                 break;
2393                         case 'P':
2394                         case 'p':
2395                                 /* AM/PM */
2396                                 if (tm.tm_hour > 11)
2397                                         snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
2398                                 else
2399                                         snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
2400                                 res = wait_file(chan,ints,nextmsg,lang);
2401                                 break;
2402                         case 'Q':
2403                                 /* Shorthand for "Today", "Yesterday", or ABdY */
2404                                 {
2405                                         struct timeval now;
2406                                         struct tm tmnow;
2407                                         time_t beg_today;
2408
2409                                         gettimeofday(&now,NULL);
2410                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
2411                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
2412                                         /* In any case, it saves not having to do ast_mktime() */
2413                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
2414                                         if (beg_today < time) {
2415                                                 /* Today */
2416                                                 res = wait_file(chan,ints, "digits/today",lang);
2417                                         } else if (beg_today - 86400 < time) {
2418                                                 /* Yesterday */
2419                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
2420                                         } else {
2421                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
2422                                         }
2423                                 }
2424                                 break;
2425                         case 'q':
2426                                 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
2427                                 {
2428                                         struct timeval now;
2429                                         struct tm tmnow;
2430                                         time_t beg_today;
2431
2432                                         gettimeofday(&now,NULL);
2433                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
2434                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
2435                                         /* In any case, it saves not having to do ast_mktime() */
2436                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
2437                                         if (beg_today < time) {
2438                                                 /* Today */
2439                                         } else if ((beg_today - 86400) < time) {
2440                                                 /* Yesterday */
2441                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
2442                                         } else if (beg_today - 86400 * 6 < time) {
2443                                                 /* Within the last week */
2444                                                 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
2445                                         } else {
2446                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
2447                                         }
2448                                 }
2449                                 break;
2450                         case 'R':
2451                                 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
2452                                 break;
2453                         case 'S':
2454                                 /* Seconds */
2455                                 if (tm.tm_sec == 0) {
2456                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
2457                                         res = wait_file(chan,ints,nextmsg,lang);
2458                                 } else if (tm.tm_sec < 10) {
2459                                         res = wait_file(chan,ints, "digits/oh",lang);
2460                                         if (!res) {
2461                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
2462                                                 res = wait_file(chan,ints,nextmsg,lang);
2463                                         }
2464                                 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
2465                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
2466                                         res = wait_file(chan,ints,nextmsg,lang);
2467                                 } else {
2468                                         int ten, one;
2469                                         ten = (tm.tm_sec / 10) * 10;
2470                                         one = (tm.tm_sec % 10);
2471                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
2472                                         res = wait_file(chan,ints,nextmsg,lang);
2473                                         if (!res) {
2474                                                 /* Fifty, not fifty-zero */
2475                                                 if (one != 0) {
2476                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
2477                                                         res = wait_file(chan,ints,nextmsg,lang);
2478                                                 }
2479                                         }
2480                                 }
2481                                 break;
2482                         case 'T':
2483                                 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
2484                                 break;
2485                         case ' ':
2486                         case '  ':
2487                                 /* Just ignore spaces and tabs */
2488                                 break;
2489                         default:
2490                                 /* Unknown character */
2491                                 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
2492                 }
2493                 /* Jump out on DTMF */
2494                 if (res) {
2495                         break;
2496                 }
2497         }
2498         return res;
2499 }
2500
2501 /* Spanish syntax */
2502 int ast_say_date_with_format_es(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
2503 {
2504         struct tm tm;
2505         int res=0, offset, sndoffset;
2506         char sndfile[256], nextmsg[256];
2507
2508         ast_localtime(&time,&tm,timezone);
2509
2510         for (offset=0 ; format[offset] != '\0' ; offset++) {
2511                 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
2512                 switch (format[offset]) {
2513                         /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
2514                         case '\'':
2515                                 /* Literal name of a sound file */
2516                                 sndoffset=0;
2517                                 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
2518                                         sndfile[sndoffset] = format[offset];
2519                                 sndfile[sndoffset] = '\0';
2520                                 snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile);
2521                                 res = wait_file(chan,ints,nextmsg,lang);
2522                                 break;
2523                         case 'A':
2524                         case 'a':
2525                                 /* Sunday - Saturday */
2526                                 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
2527                                 res = wait_file(chan,ints,nextmsg,lang);
2528                                 break;
2529                         case 'B':
2530                         case 'b':
2531                         case 'h':
2532                                 /* January - December */
2533                                 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
2534                                 res = wait_file(chan,ints,nextmsg,lang);
2535                                 break;
2536                         case 'd':
2537                         case 'e':
2538                                 /* First - Thirtyfirst */
2539                                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
2540                                 break;
2541                         case 'Y':
2542                                 /* Year */
2543                                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2544                                 break;
2545                         case 'I':
2546                         case 'l':
2547                                 /* 12-Hour */
2548                                 if (tm.tm_hour == 0)
2549                                         snprintf(nextmsg,sizeof(nextmsg), "digits/12");
2550                                 else if (tm.tm_hour > 12)
2551                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
2552                                 else
2553                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
2554                                 res = wait_file(chan,ints,nextmsg,lang);
2555                                 break;
2556                         case 'H':
2557                         case 'k':
2558                                 /* 24-Hour */
2559                                 res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL);
2560                                 if (!res) {
2561                                         if (tm.tm_hour != 0) {
2562                                                 int remainder = tm.tm_hour;
2563                                                 if (tm.tm_hour > 20) {
2564                                                         res = wait_file(chan,ints, "digits/20",lang);
2565                                                         remainder -= 20;
2566                                                 }
2567                                                 if (!res) {
2568                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
2569                                                         res = wait_file(chan,ints,nextmsg,lang);
2570                                                 }
2571                                         }
2572                                 }
2573                                 break;
2574                         case 'M':
2575                                 /* Minute */
2576                                 res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);       
2577                                 break;
2578                         case 'P':
2579                         case 'p':
2580                                 /* AM/PM */
2581                                 if (tm.tm_hour > 12)
2582                                         res = wait_file(chan, ints, "digits/p-m", lang);
2583                                 else if (tm.tm_hour  && tm.tm_hour < 12)
2584                                         res = wait_file(chan, ints, "digits/a-m", lang);
2585                                 break;
2586                         case 'Q':
2587                                 /* Shorthand for "Today", "Yesterday", or ABdY */
2588                                 {
2589                                         struct timeval now;
2590                                         struct tm tmnow;
2591                                         time_t beg_today;
2592
2593                                         gettimeofday(&now,NULL);
2594                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
2595                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
2596                                         /* In any case, it saves not having to do ast_mktime() */
2597                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
2598                                         if (beg_today < time) {
2599                                                 /* Today */
2600                                                 res = wait_file(chan,ints, "digits/today",lang);
2601                                         } else if (beg_today - 86400 < time) {
2602                                                 /* Yesterday */
2603                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
2604                                         } else {
2605                                                 res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone);
2606                                         }
2607                                 }
2608                                 break;
2609                         case 'q':
2610                                 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
2611                                 {
2612                                         struct timeval now;
2613                                         struct tm tmnow;
2614                                         time_t beg_today;
2615
2616                                         gettimeofday(&now,NULL);
2617                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
2618                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
2619                                         /* In any case, it saves not having to do ast_mktime() */
2620                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
2621                                         if (beg_today < time) {
2622                                                 /* Today */
2623                                                 res = wait_file(chan,ints, "digits/today",lang);
2624                                         } else if ((beg_today - 86400) < time) {
2625                                                 /* Yesterday */
2626                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
2627                                         } else if (beg_today - 86400 * 6 < time) {
2628                                                 /* Within the last week */
2629                                                 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
2630                                         } else {
2631                                                 res = ast_say_date_with_format(chan, time, ints, lang, "'digits/es-el' Ad 'digits/es-de' B 'digits/es-de' Y", timezone);
2632                                         }
2633                                 }
2634                                 break;
2635                         case 'R':
2636                                 res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/y' M", timezone);
2637                                 break;
2638                         case 'S':
2639                                 /* Seconds */
2640                                 if (tm.tm_sec == 0) {
2641        &n