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