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