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