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