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