Change verbosity into debug for Hebrew (and various whitespace fixes)
[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_debug(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_debug(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)
1297                                 state = 2;
1298                 } else if (num < 20000) {
1299                         snprintf(fn, sizeof(fn), "digits/%ds", (num / 1000));
1300                         num = num % 1000;
1301                         state = 3;
1302                 } else if (num < 1000000) {
1303                         res = ast_say_number_full_he(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
1304                         if (res)
1305                                 return res;
1306                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
1307                         num = num % 1000;
1308                 } else  if (num < 1000000000) {
1309                         res = ast_say_number_full_he(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
1310                         if (res)
1311                                 return res;
1312                         ast_copy_string(fn, "digits/million", sizeof(fn));
1313                         num = num % 1000000;
1314                 } else {
1315                         ast_debug(1, "Number '%d' is too big for me\n", num);
1316                         res = -1;
1317                 }
1318                 if (!res) {
1319                         if (!ast_streamfile(chan, fn, language)) {
1320                                 if ((audiofd > -1) && (ctrlfd > -1))
1321                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1322                                 else
1323                                         res = ast_waitstream(chan, ints);
1324                         }
1325                         ast_stopstream(chan);
1326                 }
1327         }
1328         return res;
1329 }
1330
1331 /*! \brief  ast_say_number_full_hu: Hungarian syntax */
1332 /* Extra sounds need:
1333         10en: "tizen"
1334         20on: "huszon"
1335 */
1336 static int ast_say_number_full_hu(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1337 {
1338         int res = 0;
1339         int playh = 0;
1340         char fn[256] = "";
1341         if (!num) 
1342                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1343
1344         /*
1345         Hungarian support
1346         like english, except numbers up to 29 are from 2 words.
1347         10 and first word of 1[1-9] and 20 and first word of 2[1-9] are different.
1348         */
1349
1350         while(!res && (num || playh)) {
1351                 if (num < 0) {
1352                         ast_copy_string(fn, "digits/minus", sizeof(fn));
1353                         if ( num > INT_MIN ) {
1354                                 num = -num;
1355                         } else {
1356                                 num = 0;
1357                         }       
1358                 } else if (playh) {
1359                         ast_copy_string(fn, "digits/hundred", sizeof(fn));
1360                         playh = 0;
1361                 } else if (num < 11 || num == 20) {
1362                         snprintf(fn, sizeof(fn), "digits/%d", num);
1363                         num = 0;
1364                 } else if (num < 20) {
1365                         ast_copy_string(fn, "digits/10en", sizeof(fn));
1366                         num -= 10;
1367                 } else if (num < 30) {
1368                         ast_copy_string(fn, "digits/20on", sizeof(fn));
1369                         num -= 20;
1370                 } else  if (num < 100) {
1371                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1372                         num %= 10;
1373                 } else {
1374                         if (num < 1000){
1375                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1376                                 playh++;
1377                                 num %= 100;
1378                         } else {
1379                                 if (num < 1000000) { /* 1,000,000 */
1380                                         res = ast_say_number_full_hu(chan, num / 1000, ints, language, audiofd, ctrlfd);
1381                                         if (res)
1382                                                 return res;
1383                                         num %= 1000;
1384                                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
1385                                 } else {
1386                                         if (num < 1000000000) { /* 1,000,000,000 */
1387                                                 res = ast_say_number_full_hu(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1388                                                 if (res)
1389                                                         return res;
1390                                                 num %= 1000000;
1391                                                 ast_copy_string(fn, "digits/million", sizeof(fn));
1392                                         } else {
1393                                                 ast_debug(1, "Number '%d' is too big for me\n", num);
1394                                                 res = -1;
1395                                         }
1396                                 }
1397                         }
1398                 }
1399                 if (!res) {
1400                         if(!ast_streamfile(chan, fn, language)) {
1401                                 if ((audiofd  > -1) && (ctrlfd > -1))
1402                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1403                                 else
1404                                         res = ast_waitstream(chan, ints);
1405                         }
1406                         ast_stopstream(chan);
1407                 }
1408         }
1409         return res;
1410 }
1411
1412 /*! \brief  ast_say_number_full_it:  Italian */
1413 static int ast_say_number_full_it(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1414 {
1415         int res = 0;
1416         int playh = 0;
1417         int tempnum = 0;
1418         char fn[256] = "";
1419
1420         if (!num)
1421                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1422
1423                 /*
1424                 Italian support
1425
1426                 Like english, numbers up to 20 are a single 'word', and others
1427                 compound, but with exceptions.
1428                 For example 21 is not twenty-one, but there is a single word in 'it'.
1429                 Idem for 28 (ie when a the 2nd part of a compund number
1430                 starts with a vowel)
1431
1432                 There are exceptions also for hundred, thousand and million.
1433                 In english 100 = one hundred, 200 is two hundred.
1434                 In italian 100 = cento , like to say hundred (without one),
1435                 200 and more are like english.
1436                 
1437                 Same applies for thousand:
1438                 1000 is one thousand in en, 2000 is two thousand.
1439                 In it we have 1000 = mille , 2000 = 2 mila 
1440
1441                 For million(s) we use the plural, if more than one
1442                 Also, one million is abbreviated in it, like on-million,
1443                 or 'un milione', not 'uno milione'.
1444                 So the right file is provided.
1445                 */
1446
1447         while (!res && (num || playh)) {
1448                         if (num < 0) {
1449                                 ast_copy_string(fn, "digits/minus", sizeof(fn));
1450                                 if ( num > INT_MIN ) {
1451                                         num = -num;
1452                                 } else {
1453                                         num = 0;
1454                                 }       
1455                         } else if (playh) {
1456                                 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1457                                 playh = 0;
1458                         } else if (num < 20) {
1459                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1460                                 num = 0;
1461                         } else if (num == 21) {
1462                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1463                                 num = 0;
1464                         } else if (num == 28) {
1465                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1466                                 num = 0;
1467                         } else if (num == 31) {
1468                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1469                                 num = 0;
1470                         } else if (num == 38) {
1471                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1472                                 num = 0;
1473                         } else if (num == 41) {
1474                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1475                                 num = 0;
1476                         } else if (num == 48) {
1477                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1478                                 num = 0;
1479                         } else if (num == 51) {
1480                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1481                                 num = 0;
1482                         } else if (num == 58) {
1483                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1484                                 num = 0;
1485                         } else if (num == 61) {
1486                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1487                                 num = 0;
1488                         } else if (num == 68) {
1489                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1490                                 num = 0;
1491                         } else if (num == 71) {
1492                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1493                                 num = 0;
1494                         } else if (num == 78) {
1495                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1496                                 num = 0;
1497                         } else if (num == 81) {
1498                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1499                                 num = 0;
1500                         } else if (num == 88) {
1501                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1502                                 num = 0;
1503                         } else if (num == 91) {
1504                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1505                                 num = 0;
1506                         } else if (num == 98) {
1507                                 snprintf(fn, sizeof(fn), "digits/%d", num);
1508                                 num = 0;
1509                         } else if (num < 100) {
1510                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1511                                 num %= 10;
1512                         } else {
1513                                 if (num < 1000) {
1514                                         if ((num / 100) > 1) {
1515                                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
1516                                                 playh++;
1517                                         } else {
1518                                                 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1519                                         }
1520                                         num %= 100;
1521                                 } else {
1522                                         if (num < 1000000) { /* 1,000,000 */
1523                                                 if ((num/1000) > 1)
1524                                                         res = ast_say_number_full_it(chan, num / 1000, ints, language, audiofd, ctrlfd);
1525                                                 if (res)
1526                                                         return res;
1527                                                 tempnum = num;
1528                                                 num %= 1000;
1529                                                 if ((tempnum / 1000) < 2)
1530                                                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
1531                                                 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
1532                                                         ast_copy_string(fn, "digits/thousands", sizeof(fn));
1533                                         } else {
1534                                                 if (num < 1000000000) { /* 1,000,000,000 */
1535                                                         if ((num / 1000000) > 1)
1536                                                                 res = ast_say_number_full_it(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1537                                                         if (res)
1538                                                                 return res;
1539                                                         tempnum = num;
1540                                                         num %= 1000000;
1541                                                         if ((tempnum / 1000000) < 2)
1542                                                                 ast_copy_string(fn, "digits/million", sizeof(fn));
1543                                                         else
1544                                                                 ast_copy_string(fn, "digits/millions", sizeof(fn));
1545                                                 } else {
1546                                                         ast_debug(1, "Number '%d' is too big for me\n", num);
1547                                                         res = -1;
1548                                                 }
1549                                         }
1550                                 }
1551                         }
1552                         if (!res) {
1553                                 if (!ast_streamfile(chan, fn, language)) {
1554                                         if ((audiofd > -1) && (ctrlfd > -1))
1555                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1556                                         else
1557                                                 res = ast_waitstream(chan, ints);
1558                                 }
1559                                 ast_stopstream(chan);
1560                         }
1561                 }
1562         return res;
1563 }
1564
1565 /*! \brief  ast_say_number_full_nl: dutch syntax */
1566 /* New files: digits/nl-en
1567  */
1568 static int ast_say_number_full_nl(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
1569 {
1570         int res = 0;
1571         int playh = 0;
1572         int units = 0;
1573         char fn[256] = "";
1574         if (!num) 
1575                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1576         while (!res && (num || playh )) {
1577                 if (num < 0) {
1578                         ast_copy_string(fn, "digits/minus", sizeof(fn));
1579                         if ( num > INT_MIN ) {
1580                                 num = -num;
1581                         } else {
1582                                 num = 0;
1583                         }       
1584                 } else if (playh) {
1585                         ast_copy_string(fn, "digits/hundred", sizeof(fn));
1586                         playh = 0;
1587                 } else if (num < 20) {
1588                         snprintf(fn, sizeof(fn), "digits/%d", num);
1589                         num = 0;
1590                 } else if (num < 100) {
1591                         units = num % 10;
1592                         if (units > 0) {
1593                                 res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
1594                                 if (res)
1595                                         return res;
1596                                 num = num - units;
1597                                 ast_copy_string(fn, "digits/nl-en", sizeof(fn));
1598                         } else {
1599                                 snprintf(fn, sizeof(fn), "digits/%d", num - units);
1600                                 num = 0;
1601                         }
1602                 } else if (num < 200) {
1603                         /* hundred, not one-hundred */
1604                         ast_copy_string(fn, "digits/hundred", sizeof(fn));
1605                         num %= 100;
1606                 } else if (num < 1000) {
1607                         snprintf(fn, sizeof(fn), "digits/%d", num / 100);
1608                         playh++;
1609                         num %= 100;
1610                 } else {
1611                         if (num < 1100) {
1612                                 /* thousand, not one-thousand */
1613                                 num %= 1000;
1614                                 ast_copy_string(fn, "digits/thousand", sizeof(fn));
1615                         } else if (num < 10000) { /* 1,100 to 9,9999 */
1616                                 res = ast_say_number_full_nl(chan, num / 100, ints, language, audiofd, ctrlfd);
1617                                 if (res)
1618                                         return res;
1619                                 num %= 100;
1620                                 ast_copy_string(fn, "digits/hundred", sizeof(fn));
1621                         } else {
1622                                 if (num < 1000000) { /* 1,000,000 */
1623                                         res = ast_say_number_full_nl(chan, num / 1000, ints, language, audiofd, ctrlfd);
1624                                         if (res)
1625                                                 return res;
1626                                         num %= 1000;
1627                                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
1628                                 } else {
1629                                         if (num < 1000000000) { /* 1,000,000,000 */
1630                                                 res = ast_say_number_full_nl(chan, num / 1000000, ints, language, audiofd, ctrlfd);
1631                                                 if (res)
1632                                                         return res;
1633                                                 num %= 1000000;
1634                                                 ast_copy_string(fn, "digits/million", sizeof(fn));
1635                                         } else {
1636                                                 ast_debug(1, "Number '%d' is too big for me\n", num);
1637                                                 res = -1;
1638                                         }
1639                                 }
1640                         }
1641                 }
1642
1643                 if (!res) {
1644                         if (!ast_streamfile(chan, fn, language)) {
1645                                 if ((audiofd > -1) && (ctrlfd > -1))
1646                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1647                                 else
1648                                         res = ast_waitstream(chan, ints);
1649                         }
1650                         ast_stopstream(chan);
1651                 }
1652         }
1653         return res;
1654 }
1655
1656 /*! \brief  ast_say_number_full_no: Norwegian syntax */
1657 /* New files:
1658  In addition to American English, the following sounds are required:  "and", "1N"
1659  */
1660 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)
1661 {
1662         int res = 0;
1663         int playh = 0;
1664         int playa = 0;
1665         int cn = 1;             /* +1 = commune; -1 = neuter */
1666         char fn[256] = "";
1667         
1668         if (!num) 
1669                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
1670         
1671         if (options && !strncasecmp(options, "n", 1)) cn = -1;
1672
1673         while (!res && (num || playh || playa )) {
1674                 /* The grammar for Norwegian numbers is the same as for English except
1675                 * for the following:
1676                 * - 1 exists in both commune ("en", file "1") and neuter ("ett", file "1N")
1677                 *   "and" before the last two digits, i.e. 2034 is "two thousand and
1678                 *   thirty-four" and 1000012 is "one million and twelve".
1679                 */
1680                 if (num < 0) {
1681                         ast_copy_string(fn, "digits/minus", sizeof(fn));
1682                         if ( num > INT_MIN ) {
1683                                 num = -num;
1684                         } else {
1685                                 num = 0;
1686                         }       
1687                 } else if (playh) {
1688                         ast_copy_string(fn, "digits/hundred", sizeof(fn));
1689                         playh = 0;
1690                 } else if (playa) {
1691                         ast_copy_string(fn, "digits/and", sizeof(fn));
1692                         playa = 0;
1693                 } else if (num == 1 && cn == -1) {
1694                         ast_copy_string(fn, "digits/1N", sizeof(fn));
1695                         num = 0;
1696                 } else if (num < 20) {
1697                         snprintf(fn, sizeof(fn), "digits/%d", num);
1698                         num = 0;
1699                 } else if (num < 100) {
1700                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
1701                         num %= 10;
1702                 } else if (num < 1000) {
1703                         int hundreds = num / 100;
1704                         if (hundreds == 1)
1705                                 ast_copy_string(fn, "digits/1N", sizeof(fn));
1706                         else
1707                                 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
1708
1709                         playh++;
1710                         num -= 100 * hundreds;
1711                         if (num)
1712                                 playa++;
1713                 } else  if (num < 1000000) {
1714                         res = ast_say_number_full_no(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
1715                         if (res)
1716                                 return res;
1717                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
1718                         num %= 1000;
1719                         if (num && num < 100)
1720                                 playa++;
1721                 } else  if (num < 1000000000) {
1722                                 int millions = num / 1000000;
1723                                 res = ast_say_number_full_no(chan, millions, ints, language, "c", audiofd, ctrlfd);
1724                                 if (res)
1725                                         return res;
1726                                 ast_copy_string(fn, "digits/million", sizeof(fn));
1727                                 num %= 1000000;
1728                                 if (num && num < 100)
1729                                         playa++;
1730                 } else {
1731                                 ast_debug(1, "Number '%d' is too big for me\n", num);
1732                                 res = -1;
1733                 }
1734                 
1735                 if (!res) {
1736                         if (!ast_streamfile(chan, fn, language)) {
1737                                 if ((audiofd > -1) && (ctrlfd > -1)) 
1738                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1739                                 else  
1740                                         res = ast_waitstream(chan, ints);
1741                         }
1742                         ast_stopstream(chan);
1743                 }
1744         }
1745         return res;
1746 }
1747
1748 typedef struct {  
1749         char *separator_dziesiatek;
1750         char *cyfry[10];
1751         char *cyfry2[10];
1752         char *setki[10];
1753         char *dziesiatki[10];
1754         char *nastki[10];  
1755         char *rzedy[3][3];
1756 } odmiana;
1757
1758 static char *pl_rzad_na_tekst(odmiana *odm, int i, int rzad)
1759 {
1760         if (rzad==0)
1761                 return "";
1762  
1763         if (i==1)
1764                 return odm->rzedy[rzad - 1][0];
1765         if ((i > 21 || i < 11) &&  i%10 > 1 && i%10 < 5)
1766                 return odm->rzedy[rzad - 1][1];
1767         else
1768                 return odm->rzedy[rzad - 1][2];
1769 }
1770
1771 static char* pl_append(char* buffer, char* str)
1772 {
1773         strcpy(buffer, str);
1774         buffer += strlen(str); 
1775         return buffer;
1776 }
1777
1778 static void pl_odtworz_plik(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, char *fn)
1779 {    
1780         char file_name[255] = "digits/";
1781         strcat(file_name, fn);
1782         ast_debug(1, "Trying to play: %s\n", file_name);
1783         if (!ast_streamfile(chan, file_name, language)) {
1784                 if ((audiofd > -1) && (ctrlfd > -1))
1785                         ast_waitstream_full(chan, ints, audiofd, ctrlfd);
1786                 else
1787                         ast_waitstream(chan, ints);
1788         }
1789         ast_stopstream(chan);
1790 }
1791
1792 static void powiedz(struct ast_channel *chan, const char *language, int audiofd, int ctrlfd, const char *ints, odmiana *odm, int rzad, int i)
1793 {
1794         /* Initialise variables to allow compilation on Debian-stable, etc */
1795         int m1000E6 = 0;
1796         int i1000E6 = 0;
1797         int m1000E3 = 0;
1798         int i1000E3 = 0;
1799         int m1000 = 0;
1800         int i1000 = 0;
1801         int m100 = 0;
1802         int i100 = 0;
1803         
1804         if (i == 0 && rzad > 0) { 
1805                 return;
1806         }
1807         if (i == 0) {
1808                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[0]);
1809                 return;
1810         }
1811
1812         m1000E6 = i % 1000000000;
1813         i1000E6 = i / 1000000000;
1814
1815         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+3, i1000E6);
1816
1817         m1000E3 = m1000E6 % 1000000;
1818         i1000E3 = m1000E6 / 1000000;
1819
1820         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+2, i1000E3);
1821
1822         m1000 = m1000E3 % 1000;
1823         i1000 = m1000E3 / 1000;
1824
1825         powiedz(chan, language, audiofd, ctrlfd, ints, odm, rzad+1, i1000);
1826
1827         m100 = m1000 % 100;
1828         i100 = m1000 / 100;
1829         
1830         if (i100>0)
1831                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->setki[i100]);
1832
1833         if ( m100 > 0 && m100 <=9 ) {
1834                 if (m1000>0)
1835                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100]);
1836                 else
1837                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry[m100]);
1838         } else if (m100 % 10 == 0) {
1839                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1840         } else if (m100 <= 19 ) {
1841                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->nastki[m100 % 10]);
1842         } else if (m100 != 0) {
1843                 if (odm->separator_dziesiatek[0]==' ') {
1844                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->dziesiatki[m100 / 10]);
1845                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, odm->cyfry2[m100 % 10]);
1846                 } else {
1847                         char buf[10];
1848                         char *b = buf;
1849                         b = pl_append(b, odm->dziesiatki[m100 / 10]);  
1850                         b = pl_append(b, odm->separator_dziesiatek);  
1851                         b = pl_append(b, odm->cyfry2[m100 % 10]); 
1852                         pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, buf);
1853                 }
1854         } 
1855
1856         if (rzad > 0) {
1857                 pl_odtworz_plik(chan, language, audiofd, ctrlfd, ints, pl_rzad_na_tekst(odm, i, rzad));
1858         }
1859 }
1860
1861 /* ast_say_number_full_pl: Polish syntax */
1862 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)
1863 /*
1864 Sounds needed:
1865 0               zero
1866 1               jeden
1867 10              dziesiec
1868 100             sto
1869 1000            tysiac
1870 1000000         milion
1871 1000000000      miliard
1872 1000000000.2    miliardy
1873 1000000000.5    miliardow
1874 1000000.2       miliony
1875 1000000.5       milionow
1876 1000.2          tysiace
1877 1000.5          tysiecy
1878 100m            stu
1879 10m             dziesieciu
1880 11              jedenascie
1881 11m             jedenastu
1882 12              dwanascie
1883 12m             dwunastu
1884 13              trzynascie
1885 13m             trzynastu
1886 14              czternascie
1887 14m             czternastu
1888 15              pietnascie
1889 15m             pietnastu
1890 16              szesnascie
1891 16m             szesnastu
1892 17              siedemnascie
1893 17m             siedemnastu
1894 18              osiemnascie
1895 18m             osiemnastu
1896 19              dziewietnascie
1897 19m             dziewietnastu
1898 1z              jedna
1899 2               dwa
1900 20              dwadziescia
1901 200             dwiescie
1902 200m            dwustu
1903 20m             dwudziestu
1904 2-1m            dwaj
1905 2-2m            dwoch
1906 2z              dwie
1907 3               trzy
1908 30              trzydziesci
1909 300             trzysta
1910 300m            trzystu
1911 30m             trzydziestu
1912 3-1m            trzej
1913 3-2m            trzech
1914 4               cztery
1915 40              czterdziesci
1916 400             czterysta
1917 400m            czterystu
1918 40m             czterdziestu
1919 4-1m            czterej
1920 4-2m            czterech
1921 5               piec
1922 50              piecdziesiat
1923 500             piecset
1924 500m            pieciuset
1925 50m             piedziesieciu
1926 5m              pieciu
1927 6               szesc
1928 60              szescdziesiat
1929 600             szescset
1930 600m            szesciuset
1931 60m             szescdziesieciu
1932 6m              szesciu
1933 7               siedem
1934 70              siedemdziesiat
1935 700             siedemset
1936 700m            siedmiuset
1937 70m             siedemdziesieciu
1938 7m              siedmiu
1939 8               osiem
1940 80              osiemdziesiat
1941 800             osiemset
1942 800m            osmiuset
1943 80m             osiemdziesieciu
1944 8m              osmiu
1945 9               dziewiec
1946 90              dziewiecdziesiat
1947 900             dziewiecset
1948 900m            dziewieciuset
1949 90m             dziewiedziesieciu
1950 9m              dziewieciu
1951 and combinations of eg.: 20_1, 30m_3m, etc...
1952
1953 */
1954 {
1955         char *zenski_cyfry[] = {"0", "1z", "2z", "3", "4", "5", "6", "7", "8", "9"};
1956
1957         char *zenski_cyfry2[] = {"0", "1", "2z", "3", "4", "5", "6", "7", "8", "9"};
1958
1959         char *meski_cyfry[] = {"0", "1", "2-1m", "3-1m", "4-1m", "5m",  /*"2-1mdwaj"*/ "6m", "7m", "8m", "9m"};
1960
1961         char *meski_cyfry2[] = {"0", "1", "2-2m", "3-2m", "4-2m", "5m", "6m", "7m", "8m", "9m"};
1962
1963         char *meski_setki[] = {"", "100m", "200m", "300m", "400m", "500m", "600m", "700m", "800m", "900m"};
1964
1965         char *meski_dziesiatki[] = {"", "10m", "20m", "30m", "40m", "50m", "60m", "70m", "80m", "90m"};
1966
1967         char *meski_nastki[] = {"", "11m", "12m", "13m", "14m", "15m", "16m", "17m", "18m", "19m"};
1968
1969         char *nijaki_cyfry[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
1970
1971         char *nijaki_cyfry2[] = {"0", "1", "2", "3", "4", "5", "6", "7", "8", "9"};
1972
1973         char *nijaki_setki[] = {"", "100", "200", "300", "400", "500", "600", "700", "800", "900"};
1974
1975         char *nijaki_dziesiatki[] = {"", "10", "20", "30", "40", "50", "60", "70", "80", "90"};
1976
1977         char *nijaki_nastki[] = {"", "11", "12", "13", "14", "15", "16", "17", "18", "19"};
1978
1979         char *rzedy[][3] = { {"1000", "1000.2", "1000.5"}, {"1000000", "1000000.2", "1000000.5"}, {"1000000000", "1000000000.2", "1000000000.5"}}; 
1980
1981         /* Initialise variables to allow compilation on Debian-stable, etc */
1982         odmiana *o;
1983
1984         static odmiana *odmiana_nieosobowa = NULL; 
1985         static odmiana *odmiana_meska = NULL; 
1986         static odmiana *odmiana_zenska = NULL; 
1987
1988         if (odmiana_nieosobowa == NULL) {
1989                 odmiana_nieosobowa = ast_malloc(sizeof(*odmiana_nieosobowa));
1990
1991                 odmiana_nieosobowa->separator_dziesiatek = " ";
1992
1993                 memcpy(odmiana_nieosobowa->cyfry, nijaki_cyfry, sizeof(odmiana_nieosobowa->cyfry));
1994                 memcpy(odmiana_nieosobowa->cyfry2, nijaki_cyfry2, sizeof(odmiana_nieosobowa->cyfry));
1995                 memcpy(odmiana_nieosobowa->setki, nijaki_setki, sizeof(odmiana_nieosobowa->setki));
1996                 memcpy(odmiana_nieosobowa->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_nieosobowa->dziesiatki));
1997                 memcpy(odmiana_nieosobowa->nastki, nijaki_nastki, sizeof(odmiana_nieosobowa->nastki));
1998                 memcpy(odmiana_nieosobowa->rzedy, rzedy, sizeof(odmiana_nieosobowa->rzedy));
1999         }
2000
2001         if (odmiana_zenska == NULL) {
2002                 odmiana_zenska = ast_malloc(sizeof(*odmiana_zenska));
2003
2004                 odmiana_zenska->separator_dziesiatek = " ";
2005
2006                 memcpy(odmiana_zenska->cyfry, zenski_cyfry, sizeof(odmiana_zenska->cyfry));
2007                 memcpy(odmiana_zenska->cyfry2, zenski_cyfry2, sizeof(odmiana_zenska->cyfry));
2008                 memcpy(odmiana_zenska->setki, nijaki_setki, sizeof(odmiana_zenska->setki));
2009                 memcpy(odmiana_zenska->dziesiatki, nijaki_dziesiatki, sizeof(odmiana_zenska->dziesiatki));
2010                 memcpy(odmiana_zenska->nastki, nijaki_nastki, sizeof(odmiana_zenska->nastki));
2011                 memcpy(odmiana_zenska->rzedy, rzedy, sizeof(odmiana_zenska->rzedy));
2012         }
2013
2014         if (odmiana_meska == NULL) {
2015                 odmiana_meska = ast_malloc(sizeof(*odmiana_meska));
2016
2017                 odmiana_meska->separator_dziesiatek = " ";
2018
2019                 memcpy(odmiana_meska->cyfry, meski_cyfry, sizeof(odmiana_meska->cyfry));
2020                 memcpy(odmiana_meska->cyfry2, meski_cyfry2, sizeof(odmiana_meska->cyfry));
2021                 memcpy(odmiana_meska->setki, meski_setki, sizeof(odmiana_meska->setki));
2022                 memcpy(odmiana_meska->dziesiatki, meski_dziesiatki, sizeof(odmiana_meska->dziesiatki));
2023                 memcpy(odmiana_meska->nastki, meski_nastki, sizeof(odmiana_meska->nastki));
2024                 memcpy(odmiana_meska->rzedy, rzedy, sizeof(odmiana_meska->rzedy));
2025         }
2026
2027         if (options) {
2028                 if (strncasecmp(options, "f", 1) == 0)
2029                         o = odmiana_zenska;
2030                 else if (strncasecmp(options, "m", 1) == 0)
2031                         o = odmiana_meska;
2032                 else
2033                         o = odmiana_nieosobowa;
2034         } else
2035                 o = odmiana_nieosobowa;
2036
2037         powiedz(chan, language, audiofd, ctrlfd, ints, o, 0, num);
2038         return 0;
2039 }
2040
2041 /* ast_say_number_full_pt: Portuguese syntax */
2042 /*      Extra sounds needed: */
2043 /*      For feminin all sound files end with F */
2044 /*      100E for 100+ something */
2045 /*      1000000S for plural */
2046 /*      pt-e for 'and' */
2047 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)
2048 {
2049         int res = 0;
2050         int playh = 0;
2051         int mf = 1;                            /* +1 = male; -1 = female */
2052         char fn[256] = "";
2053
2054         if (!num) 
2055                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2056
2057         if (options && !strncasecmp(options, "f", 1))
2058                 mf = -1;
2059
2060         while (!res && num ) {
2061                 if (num < 0) {
2062                         ast_copy_string(fn, "digits/minus", sizeof(fn));
2063                         if ( num > INT_MIN ) {
2064                                 num = -num;
2065                         } else {
2066                                 num = 0;
2067                         }       
2068                 } else if (num < 20) {
2069                         if ((num == 1 || num == 2) && (mf < 0))
2070                                 snprintf(fn, sizeof(fn), "digits/%dF", num);
2071                         else
2072                                 snprintf(fn, sizeof(fn), "digits/%d", num);
2073                         num = 0;
2074                 } else if (num < 100) {
2075                         snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
2076                         if (num % 10)
2077                                 playh = 1;
2078                         num = num % 10;
2079                 } else if (num < 1000) {
2080                         if (num == 100)
2081                                 ast_copy_string(fn, "digits/100", sizeof(fn));
2082                         else if (num < 200)
2083                                 ast_copy_string(fn, "digits/100E", sizeof(fn));
2084                         else {
2085                                 if (mf < 0 && num > 199)
2086                                         snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
2087                                 else
2088                                         snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
2089                                 if (num % 100)
2090                                         playh = 1;
2091                         }
2092                         num = num % 100;
2093                 } else if (num < 1000000) {
2094                         if (num > 1999) {
2095                                 res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
2096                                 if (res)
2097                                         return res;
2098                         }
2099                         ast_copy_string(fn, "digits/1000", sizeof(fn));
2100                         if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
2101                                 playh = 1;
2102                         num = num % 1000;
2103                 } else if (num < 1000000000) {
2104                         res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
2105                         if (res)
2106                                 return res;
2107                         if (num < 2000000)
2108                                 ast_copy_string(fn, "digits/1000000", sizeof(fn));
2109                         else
2110                                 ast_copy_string(fn, "digits/1000000S", sizeof(fn));
2111  
2112                         if ((num % 1000000) &&
2113                                 /* no thousands */
2114                                 ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
2115                                 /* no hundreds and below */
2116                                 (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
2117                                 playh = 1;
2118                         num = num % 1000000;
2119                 } else {
2120                         /* number is too big */
2121                         ast_log(LOG_WARNING, "Number '%d' is too big to say.", num);
2122                         res = -1;
2123                 }
2124                 if (!res) {
2125                         if (!ast_streamfile(chan, fn, language)) {
2126                                 if ((audiofd > -1) && (ctrlfd > -1))
2127                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd); 
2128                                 else
2129                                         res = ast_waitstream(chan, ints);
2130                         }
2131                         ast_stopstream(chan);
2132                 }
2133                 if (!res && playh) {
2134                         res = wait_file(chan, ints, "digits/pt-e", language);
2135                         ast_stopstream(chan);
2136                         playh = 0;
2137                 }
2138         }
2139         return res;
2140 }
2141
2142 /*! \brief  ast_say_number_full_se: Swedish syntax */
2143 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)
2144 {
2145         int res = 0;
2146         int playh = 0;
2147         char fn[256] = "";
2148         int cn = 1;             /* +1 = commune; -1 = neuter */
2149         if (!num) 
2150                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2151         if (options && !strncasecmp(options, "n", 1)) cn = -1;
2152
2153         while (!res && (num || playh)) {
2154                 if (num < 0) {
2155                         ast_copy_string(fn, "digits/minus", sizeof(fn));
2156                         if ( num > INT_MIN ) {
2157                                 num = -num;
2158                         } else {
2159                                 num = 0;
2160                         }       
2161                 } else if (playh) {
2162                         ast_copy_string(fn, "digits/hundred", sizeof(fn));
2163                         playh = 0;
2164                 } else if (num < 20) {
2165                         snprintf(fn, sizeof(fn), "digits/%d", num);
2166                         num = 0;
2167                 } else if (num < 100) {
2168                         snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2169                         num %= 10;
2170                 } else if (num == 1 && cn == -1) {      /* En eller ett? */
2171                         ast_copy_string(fn, "digits/1N", sizeof(fn));
2172                         num = 0;
2173                 } else {
2174                         if (num < 1000){
2175                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2176                                 playh++;
2177                                 num %= 100;
2178                         } else {
2179                                 if (num < 1000000) { /* 1,000,000 */
2180                                         res = ast_say_number_full_se(chan, num / 1000, ints, language, options, audiofd, ctrlfd);
2181                                         if (res) {
2182                                                 return res;
2183                                         }
2184                                         num %= 1000;
2185                                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
2186                                 } else {
2187                                         if (num < 1000000000) { /* 1,000,000,000 */
2188                                                 res = ast_say_number_full_se(chan, num / 1000000, ints, language, options, audiofd, ctrlfd);
2189                                                 if (res) {
2190                                                         return res;
2191                                                 }
2192                                                 num %= 1000000;
2193                                                 ast_copy_string(fn, "digits/million", sizeof(fn));
2194                                         } else {
2195                                                 ast_debug(1, "Number '%d' is too big for me\n", num);
2196                                                 res = -1;
2197                                         }
2198                                 }
2199                         }
2200                 }
2201                 if (!res) {
2202                         if (!ast_streamfile(chan, fn, language)) {
2203                                 if ((audiofd > -1) && (ctrlfd > -1))
2204                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2205                                 else
2206                                         res = ast_waitstream(chan, ints);
2207                                 ast_stopstream(chan);
2208                         }
2209                 }
2210         }
2211         return res;
2212 }
2213
2214 /*! \brief  ast_say_number_full_tw: Taiwanese / Chinese syntax */
2215 static int ast_say_number_full_tw(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2216 {
2217         int res = 0;
2218         int playh = 0;
2219         char fn[256] = "";
2220         if (!num)
2221                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2222
2223         while (!res && (num || playh)) {
2224                         if (num < 0) {
2225                                 ast_copy_string(fn, "digits/minus", sizeof(fn));
2226                                 if ( num > INT_MIN ) {
2227                                         num = -num;
2228                                 } else {
2229                                         num = 0;
2230                                 }       
2231                         } else if (playh) {
2232                                 ast_copy_string(fn, "digits/hundred", sizeof(fn));
2233                                 playh = 0;
2234                         } else  if (num < 10) {
2235                                 snprintf(fn, sizeof(fn), "digits/%d", num);
2236                                 num = 0;
2237                         } else  if (num < 100) {
2238                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
2239                                 num %= 10;
2240                         } else {
2241                                 if (num < 1000){
2242                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2243                                         playh++;
2244                                         num %= 100;
2245                                 } else {
2246                                         if (num < 1000000) { /* 1,000,000 */
2247                                                 res = ast_say_number_full_tw(chan, num / 1000, ints, language, audiofd, ctrlfd);
2248                                                 if (res)
2249                                                         return res;
2250                                                 num %= 1000;
2251                                                 ast_copy_string(fn, "digits/thousand", sizeof(fn));
2252                                         } else {
2253                                                 if (num < 1000000000) { /* 1,000,000,000 */
2254                                                         res = ast_say_number_full_tw(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2255                                                         if (res)
2256                                                                 return res;
2257                                                         num %= 1000000;
2258                                                         ast_copy_string(fn, "digits/million", sizeof(fn));
2259                                                 } else {
2260                                                         ast_debug(1, "Number '%d' is too big for me\n", num);
2261                                                         res = -1;
2262                                                 }
2263                                         }
2264                                 }
2265                         }
2266                         if (!res) {
2267                                 if (!ast_streamfile(chan, fn, language)) {
2268                                         if ((audiofd > -1) && (ctrlfd > -1))
2269                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2270                                         else
2271                                                 res = ast_waitstream(chan, ints);
2272                                 }
2273                                 ast_stopstream(chan);
2274                         }
2275         }
2276         return res;
2277 }
2278
2279
2280 /*! \brief  determine last digits for thousands/millions (ru) */
2281 static int get_lastdigits_ru(int num) {
2282         if (num < 20) {
2283                 return num;
2284         } else if (num < 100) {
2285                 return get_lastdigits_ru(num % 10);
2286         } else if (num < 1000) {
2287                 return get_lastdigits_ru(num % 100);
2288         }
2289         return 0;       /* number too big */
2290 }
2291
2292
2293 /*! \brief  ast_say_number_full_ru: Russian syntax */
2294 /*! \brief  additional files:
2295         n00.gsm                 (one hundred, two hundred, ...)
2296         thousand.gsm
2297         million.gsm
2298         thousands-i.gsm         (tisyachi)
2299         million-a.gsm           (milliona)
2300         thousands.gsm
2301         millions.gsm
2302         1f.gsm                  (odna)
2303         2f.gsm                  (dve)
2304     
2305         where 'n' from 1 to 9
2306 */
2307 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)
2308 {
2309         int res = 0;
2310         int lastdigits = 0;
2311         char fn[256] = "";
2312         if (!num) 
2313                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2314
2315         while (!res && (num)) {
2316                 if (num < 0) {
2317                         ast_copy_string(fn, "digits/minus", sizeof(fn));
2318                         if ( num > INT_MIN ) {
2319                                 num = -num;
2320                         } else {
2321                                 num = 0;
2322                         }       
2323                 } else  if (num < 20) {
2324                         if (options && strlen(options) == 1 && num < 3) {
2325                             snprintf(fn, sizeof(fn), "digits/%d%s", num, options);
2326                         } else {
2327                             snprintf(fn, sizeof(fn), "digits/%d", num);
2328                         }
2329                         num = 0;
2330                 } else  if (num < 100) {
2331                         snprintf(fn, sizeof(fn), "digits/%d", num - (num % 10));
2332                         num %= 10;
2333                 } else  if (num < 1000){
2334                         snprintf(fn, sizeof(fn), "digits/%d", num - (num % 100));
2335                         num %= 100;
2336                 } else  if (num < 1000000) { /* 1,000,000 */
2337                         lastdigits = get_lastdigits_ru(num / 1000);
2338                         /* say thousands */
2339                         if (lastdigits < 3) {
2340                                 res = ast_say_number_full_ru(chan, num / 1000, ints, language, "f", audiofd, ctrlfd);
2341                         } else {
2342                                 res = ast_say_number_full_ru(chan, num / 1000, ints, language, NULL, audiofd, ctrlfd);
2343                         }
2344                         if (res)
2345                                 return res;
2346                         if (lastdigits == 1) {
2347                                 ast_copy_string(fn, "digits/thousand", sizeof(fn));
2348                         } else if (lastdigits > 1 && lastdigits < 5) {
2349                                 ast_copy_string(fn, "digits/thousands-i", sizeof(fn));
2350                         } else {
2351                                 ast_copy_string(fn, "digits/thousands", sizeof(fn));
2352                         }
2353                         num %= 1000;
2354                 } else  if (num < 1000000000) { /* 1,000,000,000 */
2355                         lastdigits = get_lastdigits_ru(num / 1000000);
2356                         /* say millions */
2357                         res = ast_say_number_full_ru(chan, num / 1000000, ints, language, NULL, audiofd, ctrlfd);
2358                         if (res)
2359                                 return res;
2360                         if (lastdigits == 1) {
2361                                 ast_copy_string(fn, "digits/million", sizeof(fn));
2362                         } else if (lastdigits > 1 && lastdigits < 5) {
2363                                 ast_copy_string(fn, "digits/million-a", sizeof(fn));
2364                         } else {
2365                                 ast_copy_string(fn, "digits/millions", sizeof(fn));
2366                         }
2367                         num %= 1000000;
2368                 } else {
2369                         ast_debug(1, "Number '%d' is too big for me\n", num);
2370                         res = -1;
2371                 }
2372                 if (!res) {
2373                         if (!ast_streamfile(chan, fn, language)) {
2374                                 if ((audiofd  > -1) && (ctrlfd > -1))
2375                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2376                                 else
2377                                         res = ast_waitstream(chan, ints);
2378                         }
2379                         ast_stopstream(chan);
2380                 }
2381         }
2382         return res;
2383 }
2384
2385 static int ast_say_number_full_th(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2386 {
2387         int res = 0;
2388         int playh = 0;
2389         char fn[256] = "";
2390         if (!num) 
2391                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2392
2393         while(!res && (num || playh)) {
2394                 if (num < 0) {
2395                         ast_copy_string(fn, "digits/lop", sizeof(fn));
2396                         if ( num > INT_MIN ) {
2397                                 num = -num;
2398                         } else {
2399                                 num = 0;
2400                         }       
2401                 } else if (playh) {
2402                         ast_copy_string(fn, "digits/roi", sizeof(fn));
2403                         playh = 0;
2404                 } else if (num < 100) {
2405                         if ((num <= 20) || ((num % 10) == 1)) {
2406                                 snprintf(fn, sizeof(fn), "digits/%d", num);
2407                                 num = 0;
2408                         } else {
2409                                 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
2410                                 num %= 10;
2411                         }
2412                 } else if (num < 1000) {
2413                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
2414                         playh++;
2415                         num %= 100;
2416                 } else if (num < 10000) { /* 10,000 */
2417                         res = ast_say_number_full_th(chan, num / 1000, ints, language, audiofd, ctrlfd);
2418                         if (res)
2419                                 return res;
2420                         num %= 1000;
2421                         ast_copy_string(fn, "digits/pan", sizeof(fn));
2422                 } else if (num < 100000) { /* 100,000 */
2423                         res = ast_say_number_full_th(chan, num / 10000, ints, language, audiofd, ctrlfd);
2424                         if (res)
2425                                 return res;
2426                         num %= 10000;
2427                         ast_copy_string(fn, "digits/muan", sizeof(fn));
2428                 } else if (num < 1000000) { /* 1,000,000 */
2429                         res = ast_say_number_full_th(chan, num / 100000, ints, language, audiofd, ctrlfd);
2430                         if (res)
2431                                 return res;
2432                         num %= 100000;
2433                         ast_copy_string(fn, "digits/san", sizeof(fn));
2434                 } else {
2435                         res = ast_say_number_full_th(chan, num / 1000000, ints, language, audiofd, ctrlfd);
2436                         if (res)
2437                                 return res;
2438                         num %= 1000000;
2439                         ast_copy_string(fn, "digits/larn", sizeof(fn));
2440                 }
2441                 if (!res) {
2442                         if(!ast_streamfile(chan, fn, language)) {
2443                                 if ((audiofd  > -1) && (ctrlfd > -1))
2444                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2445                                 else
2446                                         res = ast_waitstream(chan, ints);
2447                         }
2448                         ast_stopstream(chan);
2449                 }
2450         }
2451         return res;
2452 }
2453
2454 /*! \brief  ast_say_enumeration_full: call language-specific functions */
2455 /* Called from AGI */
2456 static int say_enumeration_full(struct ast_channel *chan, int num, const char *ints, const char *language, const char *options, int audiofd, int ctrlfd)
2457 {
2458         if (!strcasecmp(language, "en") ) {     /* English syntax */
2459            return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2460         } else if (!strcasecmp(language, "da") ) {      /* Danish syntax */
2461            return(ast_say_enumeration_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
2462         } else if (!strcasecmp(language, "de") ) {      /* German syntax */
2463            return(ast_say_enumeration_full_de(chan, num, ints, language, options, audiofd, ctrlfd));
2464         } 
2465         
2466         /* Default to english */
2467         return(ast_say_enumeration_full_en(chan, num, ints, language, audiofd, ctrlfd));
2468 }
2469
2470 /*! \brief  ast_say_enumeration_full_en: English syntax */
2471 /* This is the default syntax, if no other syntax defined in this file is used */
2472 static int ast_say_enumeration_full_en(struct ast_channel *chan, int num, const char *ints, const char *language, int audiofd, int ctrlfd)
2473 {
2474         int res = 0, t = 0;
2475         char fn[256] = "";
2476         
2477         while (!res && num) {
2478                 if (num < 0) {
2479                         ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */
2480                         if ( num > INT_MIN ) {
2481                                 num = -num;
2482                         } else {
2483                                 num = 0;
2484                         }       
2485                 } else if (num < 20) {
2486                         snprintf(fn, sizeof(fn), "digits/h-%d", num);
2487                         num = 0;
2488                 } else if (num < 100) { 
2489                         int tens = num / 10;
2490                         num = num % 10;
2491                         if (num == 0) {
2492                                 snprintf(fn, sizeof(fn), "digits/h-%d", (tens * 10));
2493                         } else {
2494                                 snprintf(fn, sizeof(fn), "digits/%d", (tens * 10));
2495                         }
2496                 } else if (num < 1000) {
2497                         int hundreds = num / 100;
2498                         num = num % 100;
2499                         if (hundreds > 1 || t == 1) {
2500                                 res = ast_say_number_full_en(chan, hundreds, ints, language, audiofd, ctrlfd);
2501                         }                       
2502                         if (res)
2503                                 return res;
2504                         if (num) {
2505                                 ast_copy_string(fn, "digits/hundred", sizeof(fn));
2506                         } else {
2507                                 ast_copy_string(fn, "digits/h-hundred", sizeof(fn));
2508                         }
2509                 } else if (num < 1000000) {
2510                         int thousands = num / 1000;
2511                         num = num % 1000;
2512                         if (thousands > 1 || t == 1) {
2513                                 res = ast_say_number_full_en(chan, thousands, ints, language, audiofd, ctrlfd);
2514                         }
2515                         if (res)
2516                                 return res;
2517                         if (num) {                                      
2518                                 ast_copy_string(fn, "digits/thousand", sizeof(fn));
2519                         } else {
2520                                 ast_copy_string(fn, "digits/h-thousand", sizeof(fn));
2521                         }
2522                         t = 1;
2523                 } else if (num < 1000000000) {
2524                         int millions = num / 1000000;
2525                         num = num % 1000000;
2526                         t = 1;
2527                         res = ast_say_number_full_en(chan, millions, ints, language, audiofd, ctrlfd);
2528                         if (res)
2529                                 return res;
2530                         if (num) {                                      
2531                                 ast_copy_string(fn, "digits/million", sizeof(fn));
2532                         } else {
2533                                 ast_copy_string(fn, "digits/h-million", sizeof(fn));
2534                         }
2535                 } else if (num < INT_MAX) {
2536                         int billions = num / 1000000000;
2537                         num = num % 1000000000;
2538                         t = 1;
2539                         res = ast_say_number_full_en(chan, billions, ints, language, audiofd, ctrlfd);
2540                         if (res)
2541                                 return res;
2542                         if (num) {                                      
2543                                 ast_copy_string(fn, "digits/billion", sizeof(fn));
2544                         } else {
2545                                 ast_copy_string(fn, "digits/h-billion", sizeof(fn));
2546                         }
2547                 } else if (num == INT_MAX) {
2548                         ast_copy_string(fn, "digits/h-last", sizeof(fn));
2549                         num = 0;
2550                 } else {
2551                         ast_debug(1, "Number '%d' is too big for me\n", num);
2552                         res = -1;
2553                 }
2554
2555                 if (!res) {
2556                         if (!ast_streamfile(chan, fn, language)) {
2557                                 if ((audiofd > -1) && (ctrlfd > -1)) {
2558                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2559                                 } else {
2560                                         res = ast_waitstream(chan, ints);
2561                                 }
2562                         }
2563                         ast_stopstream(chan);
2564                 }
2565         }
2566         return res;
2567 }
2568
2569 /*! \brief  ast_say_enumeration_full_da: Danish syntax */
2570 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)
2571 {
2572         /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2573         int res = 0, t = 0;
2574         char fn[256] = "", fna[256] = "";
2575         char *gender;
2576
2577         if (options && !strncasecmp(options, "f", 1)) {
2578                 gender = "F";
2579         } else if (options && !strncasecmp(options, "n", 1)) {
2580                 gender = "N";
2581         } else {
2582                 gender = "";
2583         }
2584
2585         if (!num) 
2586                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2587
2588         while (!res && num) {
2589                 if (num < 0) {
2590                         ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */
2591                         if ( num > INT_MIN ) {
2592                                 num = -num;
2593                         } else {
2594                                 num = 0;
2595                         }       
2596                 } else if (num < 100 && t) {
2597                         ast_copy_string(fn, "digits/and", sizeof(fn));
2598                         t = 0;
2599                 } else if (num < 20) {
2600                         snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2601                         num = 0;
2602                 } else if (num < 100) {
2603                         int ones = num % 10;
2604                         if (ones) {
2605                                 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2606                                 num -= ones;
2607                         } else {
2608                                 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2609                                 num = 0;
2610                         }
2611                 } else if (num == 100 && t == 0) {
2612                         snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2613                         num = 0;
2614                 } else if (num < 1000) {
2615                         int hundreds = num / 100;
2616                         num = num % 100;
2617                         if (hundreds == 1) {
2618                                 ast_copy_string(fn, "digits/1N", sizeof(fn));
2619                         } else {
2620                                 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2621                         }
2622                         if (num) {                                      
2623                                 ast_copy_string(fna, "digits/hundred", sizeof(fna));
2624                         } else {
2625                                 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2626                         }
2627                         t = 1;
2628                 } else  if (num < 1000000) {
2629                         int thousands = num / 1000;
2630                         num = num % 1000;
2631                         if (thousands == 1) {
2632                                 if (num) {                                      
2633                                         ast_copy_string(fn, "digits/1N", sizeof(fn));
2634                                         ast_copy_string(fna, "digits/thousand", sizeof(fna));
2635                                 } else {
2636                                         if (t) {
2637                                                 ast_copy_string(fn, "digits/1N", sizeof(fn));
2638                                                 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2639                                         } else {
2640                                                 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2641                                         }
2642                                 }
2643                         } else {
2644                                 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2645                                 if (res) {
2646                                         return res;
2647                                 }
2648                                 if (num) {                                      
2649                                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
2650                                 } else {
2651                                         snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2652                                 }
2653                         }
2654                         t = 1;
2655                 } else if (num < 1000000000) {
2656                         int millions = num / 1000000;
2657                         num = num % 1000000;
2658                         if (millions == 1) {
2659                                 if (num) {                                      
2660                                         ast_copy_string(fn, "digits/1F", sizeof(fn));
2661                                         ast_copy_string(fna, "digits/million", sizeof(fna));
2662                                 } else {
2663                                         ast_copy_string(fn, "digits/1N", sizeof(fn));
2664                                         snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2665                                 }
2666                         } else {
2667                                 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2668                                 if (res) {
2669                                         return res;
2670                                 }
2671                                 if (num) {                                      
2672                                         ast_copy_string(fn, "digits/millions", sizeof(fn));
2673                                 } else {
2674                                         snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2675                                 }
2676                         }
2677                         t = 1;
2678                 } else if (num < INT_MAX) {
2679                         int billions = num / 1000000000;
2680                         num = num % 1000000000;
2681                         if (billions == 1) {
2682                                 if (num) {                                      
2683                                         ast_copy_string(fn, "digits/1F", sizeof(fn));
2684                                         ast_copy_string(fna, "digits/milliard", sizeof(fna));
2685                                 } else {
2686                                         ast_copy_string(fn, "digits/1N", sizeof(fn));
2687                                         snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2688                                 }
2689                         } else {
2690                                 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2691                                 if (res)
2692                                         return res;
2693                                 if (num) {                                      
2694                                         ast_copy_string(fn, "digits/milliards", sizeof(fna));
2695                                 } else {
2696                                         snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2697                                 }
2698                         }
2699                         t = 1;
2700                 } else if (num == INT_MAX) {
2701                         snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2702                         num = 0;
2703                 } else {
2704                         ast_debug(1, "Number '%d' is too big for me\n", num);
2705                         res = -1;
2706                 }
2707
2708                 if (!res) {
2709                         if (!ast_streamfile(chan, fn, language)) {
2710                                 if ((audiofd > -1) && (ctrlfd > -1)) 
2711                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2712                                 else  
2713                                         res = ast_waitstream(chan, ints);
2714                         }
2715                         ast_stopstream(chan);
2716                         if (!res) {
2717                                 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2718                                         if ((audiofd > -1) && (ctrlfd > -1)) {
2719                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2720                                         } else {
2721                                                 res = ast_waitstream(chan, ints);
2722                                         }
2723                                 }
2724                                 ast_stopstream(chan);
2725                                 strcpy(fna, "");
2726                         }
2727                 }
2728         }
2729         return res;
2730 }
2731
2732 /*! \brief  ast_say_enumeration_full_de: German syntax */
2733 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)
2734 {
2735         /* options can be: '' or 'm' male gender; 'f' female gender; 'n' neuter gender; 'p' plural */
2736         int res = 0, t = 0;
2737         char fn[256] = "", fna[256] = "";
2738         char *gender;
2739
2740         if (options && !strncasecmp(options, "f", 1)) {
2741                 gender = "F";
2742         } else if (options && !strncasecmp(options, "n", 1)) {
2743                 gender = "N";
2744         } else {
2745                 gender = "";
2746         }
2747
2748         if (!num) 
2749                 return ast_say_digits_full(chan, 0, ints, language, audiofd, ctrlfd);
2750
2751         while (!res && num) {
2752                 if (num < 0) {
2753                         ast_copy_string(fn, "digits/minus", sizeof(fn)); /* kind of senseless for enumerations, but our best effort for error checking */
2754                         if ( num > INT_MIN ) {
2755                                 num = -num;
2756                         } else {
2757                                 num = 0;
2758                         }       
2759                 } else if (num < 100 && t) {
2760                         ast_copy_string(fn, "digits/and", sizeof(fn));
2761                         t = 0;
2762                 } else if (num < 20) {
2763                         snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2764                         num = 0;
2765                 } else if (num < 100) {
2766                         int ones = num % 10;
2767                         if (ones) {
2768                                 snprintf(fn, sizeof(fn), "digits/%d-and", ones);
2769                                 num -= ones;
2770                         } else {
2771                                 snprintf(fn, sizeof(fn), "digits/h-%d%s", num, gender);
2772                                 num = 0;
2773                         }
2774                 } else if (num == 100 && t == 0) {
2775                         snprintf(fn, sizeof(fn), "digits/h-hundred%s", gender);
2776                         num = 0;
2777                 } else if (num < 1000) {
2778                         int hundreds = num / 100;
2779                         num = num % 100;
2780                         if (hundreds == 1) {
2781                                 ast_copy_string(fn, "digits/1N", sizeof(fn));
2782                         } else {
2783                                 snprintf(fn, sizeof(fn), "digits/%d", hundreds);
2784                         }
2785                         if (num) {                                      
2786                                 ast_copy_string(fna, "digits/hundred", sizeof(fna));
2787                         } else {
2788                                 snprintf(fna, sizeof(fna), "digits/h-hundred%s", gender);
2789                         }
2790                         t = 1;
2791                 } else  if (num < 1000000) {
2792                         int thousands = num / 1000;
2793                         num = num % 1000;
2794                         if (thousands == 1) {
2795                                 if (num) {                                      
2796                                         ast_copy_string(fn, "digits/1N", sizeof(fn));
2797                                         ast_copy_string(fna, "digits/thousand", sizeof(fna));
2798                                 } else {
2799                                         if (t) {
2800                                                 ast_copy_string(fn, "digits/1N", sizeof(fn));
2801                                                 snprintf(fna, sizeof(fna), "digits/h-thousand%s", gender);
2802                                         } else {
2803                                                 snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2804                                         }
2805                                 }
2806                         } else {
2807                                 res = ast_say_number_full_de(chan, thousands, ints, language, options, audiofd, ctrlfd);
2808                                 if (res) {
2809                                         return res;
2810                                 }
2811                                 if (num) {                                      
2812                                         ast_copy_string(fn, "digits/thousand", sizeof(fn));
2813                                 } else {
2814                                         snprintf(fn, sizeof(fn), "digits/h-thousand%s", gender);
2815                                 }
2816                         }
2817                         t = 1;
2818                 } else if (num < 1000000000) {
2819                         int millions = num / 1000000;
2820                         num = num % 1000000;
2821                         if (millions == 1) {
2822                                 if (num) {                                      
2823                                         ast_copy_string(fn, "digits/1F", sizeof(fn));
2824                                         ast_copy_string(fna, "digits/million", sizeof(fna));
2825                                 } else {
2826                                         ast_copy_string(fn, "digits/1N", sizeof(fn));
2827                                         snprintf(fna, sizeof(fna), "digits/h-million%s", gender);
2828                                 }
2829                         } else {
2830                                 res = ast_say_number_full_de(chan, millions, ints, language, options, audiofd, ctrlfd);
2831                                 if (res) {
2832                                         return res;
2833                                 }
2834                                 if (num) {                                      
2835                                         ast_copy_string(fn, "digits/millions", sizeof(fn));
2836                                 } else {
2837                                         snprintf(fn, sizeof(fn), "digits/h-million%s", gender);
2838                                 }
2839                         }
2840                         t = 1;
2841                 } else if (num < INT_MAX) {
2842                         int billions = num / 1000000000;
2843                         num = num % 1000000000;
2844                         if (billions == 1) {
2845                                 if (num) {                                      
2846                                         ast_copy_string(fn, "digits/1F", sizeof(fn));
2847                                         ast_copy_string(fna, "digits/milliard", sizeof(fna));
2848                                 } else {
2849                                         ast_copy_string(fn, "digits/1N", sizeof(fn));
2850                                         snprintf(fna, sizeof(fna), "digits/h-milliard%s", gender);
2851                                 }
2852                         } else {
2853                                 res = ast_say_number_full_de(chan, billions, ints, language, options, audiofd, ctrlfd);
2854                                 if (res)
2855                                         return res;
2856                                 if (num) {                                      
2857                                         ast_copy_string(fn, "digits/milliards", sizeof(fna));
2858                                 } else {
2859                                         snprintf(fn, sizeof(fna), "digits/h-milliard%s", gender);
2860                                 }
2861                         }
2862                         t = 1;
2863                 } else if (num == INT_MAX) {
2864                         snprintf(fn, sizeof(fn), "digits/h-last%s", gender);
2865                         num = 0;
2866                 } else {
2867                         ast_debug(1, "Number '%d' is too big for me\n", num);
2868                         res = -1;
2869                 }
2870
2871                 if (!res) {
2872                         if (!ast_streamfile(chan, fn, language)) {
2873                                 if ((audiofd > -1) && (ctrlfd > -1)) 
2874                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2875                                 else  
2876                                         res = ast_waitstream(chan, ints);
2877                         }
2878                         ast_stopstream(chan);
2879                         if (!res) {
2880                                 if (strlen(fna) != 0 && !ast_streamfile(chan, fna, language)) {
2881                                         if ((audiofd > -1) && (ctrlfd > -1)) {
2882                                                 res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
2883                                         } else {
2884                                                 res = ast_waitstream(chan, ints);
2885                                         }
2886                                 }
2887                                 ast_stopstream(chan);
2888                                 strcpy(fna, "");
2889                         }
2890                 }
2891         }
2892         return res;
2893 }
2894
2895 static int say_date(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2896 {
2897         if (!strcasecmp(lang, "en") ) { /* English syntax */
2898                 return(ast_say_date_en(chan, t, ints, lang));
2899         } else if (!strcasecmp(lang, "da") ) {  /* Danish syntax */
2900                 return(ast_say_date_da(chan, t, ints, lang));
2901         } else if (!strcasecmp(lang, "de") ) {  /* German syntax */
2902                 return(ast_say_date_de(chan, t, ints, lang));
2903         } else if (!strcasecmp(lang, "fr") ) {  /* French syntax */
2904                 return(ast_say_date_fr(chan, t, ints, lang));
2905         } else if (!strcasecmp(lang, "hu") ) {  /* Hungarian syntax */
2906                 return(ast_say_date_hu(chan, t, ints, lang));
2907         } else if (!strcasecmp(lang, "nl") ) {  /* Dutch syntax */
2908                 return(ast_say_date_nl(chan, t, ints, lang));
2909         } else if (!strcasecmp(lang, "pt") || !strcasecmp(lang, "pt_BR")) {     /* Portuguese syntax */
2910                 return(ast_say_date_pt(chan, t, ints, lang));
2911         } else if (!strcasecmp(lang, "gr") ) {                          /* Greek syntax */
2912                 return(ast_say_date_gr(chan, t, ints, lang));
2913         } else if (!strcasecmp(lang, "th") ) {  /* Thai syntax */
2914                 return(ast_say_date_th(chan, t, ints, lang));
2915         } else if (!strcasecmp(lang, "ge") ) {  /* Georgian syntax */
2916                 return(ast_say_date_ge(chan, t, ints, lang));
2917         }
2918
2919         /* Default to English */
2920         return(ast_say_date_en(chan, t, ints, lang));
2921 }
2922
2923 /* English syntax */
2924 int ast_say_date_en(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2925 {
2926         struct ast_tm tm;
2927         struct timeval tv = { t, 0 };
2928         char fn[256];
2929         int res = 0;
2930         ast_localtime(&tv, &tm, NULL);
2931         if (!res) {
2932                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2933                 res = ast_streamfile(chan, fn, lang);
2934                 if (!res)
2935                         res = ast_waitstream(chan, ints);
2936         }
2937         if (!res) {
2938                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2939                 res = ast_streamfile(chan, fn, lang);
2940                 if (!res)
2941                         res = ast_waitstream(chan, ints);
2942         }
2943         if (!res)
2944                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2945         if (!res)
2946                 res = ast_waitstream(chan, ints);
2947         if (!res)
2948                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
2949         return res;
2950 }
2951
2952 /* Danish syntax */
2953 int ast_say_date_da(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
2954 {
2955         struct timeval tv = { t, 0 };
2956         struct ast_tm tm;
2957         char fn[256];
2958         int res = 0;
2959         ast_localtime(&tv, &tm, NULL);
2960         if (!res) {
2961                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
2962                 res = ast_streamfile(chan, fn, lang);
2963                 if (!res)
2964                         res = ast_waitstream(chan, ints);
2965         }
2966         if (!res)
2967                 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
2968         if (!res)
2969                 res = ast_waitstream(chan, ints);
2970         if (!res) {
2971                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
2972                 res = ast_streamfile(chan, fn, lang);
2973                 if (!res)
2974                         res = ast_waitstream(chan, ints);
2975         }
2976         if (!res) {
2977                 /* Year */
2978                 int year = tm.tm_year + 1900;
2979                 if (year > 1999) {      /* year 2000 and later */
2980                         res = ast_say_number(chan, year, ints, lang, (char *) NULL);    
2981                 } else {
2982                         if (year < 1100) {
2983                                 /* I'm not going to handle 1100 and prior */
2984                                 /* We'll just be silent on the year, instead of bombing out. */
2985                         } else {
2986                             /* year 1100 to 1999. will anybody need this?!? */
2987                                 snprintf(fn, sizeof(fn), "digits/%d", (year / 100));
2988                                 res = wait_file(chan, ints, fn, lang);
2989                                 if (!res) {
2990                                         res = wait_file(chan, ints, "digits/hundred", lang);
2991                                         if (!res && year % 100 != 0) {
2992                                                 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);    
2993                                         }
2994                                 }
2995                         }
2996                 }
2997         }
2998         return res;
2999 }
3000
3001 /* German syntax */
3002 int ast_say_date_de(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
3003 {
3004         struct timeval tv = { t, 0 };
3005         struct ast_tm tm;
3006         char fn[256];
3007         int res = 0;
3008         ast_localtime(&tv, &tm, NULL);
3009         if (!res) {
3010                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
3011                 res = ast_streamfile(chan, fn, lang);
3012                 if (!res)
3013                         res = ast_waitstream(chan, ints);
3014         }
3015         if (!res)
3016                 res = ast_say_enumeration(chan, tm.tm_mday, ints, lang, (char * ) NULL);
3017         if (!res)
3018                 res = ast_waitstream(chan, ints);
3019         if (!res) {
3020                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
3021                 res = ast_streamfile(chan, fn, lang);
3022                 if (!res)
3023                         res = ast_waitstream(chan, ints);
3024         }
3025         if (!res) {
3026                 /* Year */
3027                 int year = tm.tm_year + 1900;
3028                 if (year > 1999) {      /* year 2000 and later */
3029                         res = ast_say_number(chan, year, ints, lang, (char *) NULL);    
3030                 } else {
3031                         if (year < 1100) {
3032                                 /* I'm not going to handle 1100 and prior */
3033                                 /* We'll just be silent on the year, instead of bombing out. */
3034                         } else {
3035                             /* year 1100 to 1999. will anybody need this?!? */
3036                             /* say 1967 as 'neunzehn hundert sieben und sechzig' */
3037                                 snprintf(fn, sizeof(fn), "digits/%d", (year / 100) );
3038                                 res = wait_file(chan, ints, fn, lang);
3039                                 if (!res) {
3040                                         res = wait_file(chan, ints, "digits/hundred", lang);
3041                                         if (!res && year % 100 != 0) {
3042                                                 res = ast_say_number(chan, (year % 100), ints, lang, (char *) NULL);    
3043                                         }
3044                                 }
3045                         }
3046                 }
3047         }
3048         return res;
3049 }
3050
3051 /* Hungarian syntax */
3052 int ast_say_date_hu(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
3053 {
3054         struct timeval tv = { t, 0 };
3055         struct ast_tm tm;
3056         char fn[256];
3057         int res = 0;
3058         ast_localtime(&tv, &tm, NULL);
3059
3060         if (!res)
3061                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
3062         if (!res)
3063                 res = ast_waitstream(chan, ints);
3064         if (!res) {
3065                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
3066                 res = ast_streamfile(chan, fn, lang);
3067                 if (!res)
3068                         res = ast_waitstream(chan, ints);
3069         }       
3070         if (!res)
3071                 ast_say_number(chan, tm.tm_mday , ints, lang, (char *) NULL);
3072         if (!res)
3073                 res = ast_waitstream(chan, ints);
3074         if (!res) {
3075                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
3076                 res = ast_streamfile(chan, fn, lang);
3077                 if (!res)
3078                         res = ast_waitstream(chan, ints);               
3079         }
3080         return res;
3081 }
3082
3083 /* French syntax */
3084 int ast_say_date_fr(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
3085 {
3086         struct timeval tv = { t, 0 };
3087         struct ast_tm tm;
3088         char fn[256];
3089         int res = 0;
3090         ast_localtime(&tv, &tm, NULL);
3091         if (!res) {
3092                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
3093                 res = ast_streamfile(chan, fn, lang);
3094                 if (!res)
3095                         res = ast_waitstream(chan, ints);
3096         }
3097         if (!res)
3098                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
3099         if (!res)
3100                 res = ast_waitstream(chan, ints);
3101         if (!res) {
3102                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
3103                 res = ast_streamfile(chan, fn, lang);
3104                 if (!res)
3105                         res = ast_waitstream(chan, ints);
3106         }
3107         if (!res)
3108                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
3109         return res;
3110 }
3111
3112 /* Dutch syntax */
3113 int ast_say_date_nl(struct ast_channel *chan, time_t t, const char *ints, const char *lang)
3114 {
3115         struct timeval tv = { t, 0 };
3116         struct ast_tm tm;
3117         char fn[256];
3118         int res = 0;
3119         ast_localtime(&tv, &tm, NULL);
3120         if (!res) {
3121                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
3122                 res = ast_streamfile(chan, fn, lang);
3123                 if (!res)
3124      &