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