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