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