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