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