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