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