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