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