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