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