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