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