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