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