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