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