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