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