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