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