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