Merge german say number enhancements (bug #1532) thanks!
[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
14 #include <sys/types.h>
15 #include <string.h>
16 #include <stdlib.h>
17 #include <netinet/in.h>
18 #include <time.h>
19 #include <asterisk/file.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/logger.h>
22 #include <asterisk/say.h>
23 #include <asterisk/lock.h>
24 #include <asterisk/localtime.h>
25 #include "asterisk.h"
26 #include <stdio.h>
27
28
29 /* Forward declaration */
30 static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang);
31
32 int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
33 {
34         /* XXX Merge with full version? XXX */
35         char fn[256] = "";
36         int num = 0;
37         int res = 0;
38         while(fn2[num] && !res) {
39                 fn[0] = '\0';
40                 switch (fn2[num]) {
41                         case ('*'):
42                                 snprintf(fn, sizeof(fn), "digits/star");
43                                 break;
44                         case ('#'):
45                                 snprintf(fn, sizeof(fn), "digits/pound");
46                                 break;
47                         default:
48                                 if((fn2[num] >= '0') && (fn2[num] <= '9')){ /* Must be in {0-9} */       
49                                         snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
50                                 }
51                         }
52                 if(strlen(fn)){ /* if length == 0, then skip this digit as it is invalid */
53                         res = ast_streamfile(chan, fn, lang);
54                         if (!res) 
55                                 res = ast_waitstream(chan, ints);
56                         ast_stopstream(chan);
57                 }
58                 num++;
59         }
60         return res;
61 }
62
63 int ast_say_digit_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd)
64 {
65         char fn[256] = "";
66         int num = 0;
67         int res = 0;
68         while(fn2[num] && !res) {
69                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
70                 res = ast_streamfile(chan, fn, lang);
71                 if (!res) 
72                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
73                 ast_stopstream(chan);
74                 num++;
75         }
76         return res;
77 }
78
79 int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang)
80 {
81         /* XXX Should I be merged with say_digits_full XXX */
82         char fn2[256];
83         snprintf(fn2, sizeof(fn2), "%d", num);
84         return ast_say_digit_str(chan, fn2, ints, lang);
85 }
86
87 int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd)
88 {
89         char fn2[256];
90         snprintf(fn2, sizeof(fn2), "%d", num);
91         return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
92 }
93
94 /* Forward declarations */
95 /* Syntaxes supported, not really language codes.
96       da - Danish
97       de - German
98       en - English, Swedish, Norwegian
99       es - Spanish
100       fr - French
101       it - Italian
102       nl - Dutch
103       pt - Portuguese
104
105  Gender:
106  For Portuguese, we're using m & f options to saynumber() to indicate if the gender is masculine or feminine.
107  For Danish, we're using c & n options to saynumber() to indicate if the gender is commune or neutrum.
108  This still needs to be implemented for French, Spanish & German.
109
110  Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
111
112  See contrib/i18n.testsuite.conf for some examples of the different syntaxes
113
114  OEJ 2004-04-25
115  FPB 2004-05-01
116 */
117
118 static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
119 static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd);
120 static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
121 static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
122 static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
123 static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
124 static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
125 static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd);
126
127 /*--- ast_say_number_full: call language-specific functions */
128 /* Called from AGI */
129 int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
130 {
131         char *options=(char *) NULL;    /* While waiting for a general hack for agi */
132
133         if (!strcasecmp(language, "no") || !strcasecmp(language,"se") || !strcasecmp(language,"en") ) {
134            return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
135         } else if (!strcasecmp(language, "fr") ) {      /* French syntax */
136            return(ast_say_number_full_fr(chan, num, ints, language, audiofd, ctrlfd));
137         } else if (!strcasecmp(language, "de") ) {      /* German syntax */
138            return(ast_say_number_full_de(chan, num, ints, language, audiofd, ctrlfd));
139         } else if (!strcasecmp(language, "da") ) {      /* Danish syntax */
140            return(ast_say_number_full_da(chan, num, ints, language, options, audiofd, ctrlfd));
141         } else if (!strcasecmp(language, "it") ) {      /* Italian syntax */
142            return(ast_say_number_full_it(chan, num, ints, language, audiofd, ctrlfd));
143         } else if (!strcasecmp(language, "pt") ) {      /* Portuguese syntax */
144            return(ast_say_number_full_pt(chan, num, ints, language, options, audiofd, ctrlfd));
145         } else if (!strcasecmp(language, "es") ) {      /* Spanish syntax */
146            return(ast_say_number_full_es(chan, num, ints, language, audiofd, ctrlfd));
147         } else if (!strcasecmp(language, "nl") ) {      /* Dutch syntax */
148            return(ast_say_number_full_nl(chan, num, ints, language, audiofd, ctrlfd));
149         }
150
151         /* Default to english */
152         return(ast_say_number_full_en(chan, num, ints, language, audiofd, ctrlfd));
153 }
154
155 /*--- ast_say_number: call language-specific functions without file descriptors */
156 int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language, char *options)
157 {
158         if (!strcasecmp(language, "no") || !strcasecmp(language,"se") || !strcasecmp(language,"en") ) {
159            return(ast_say_number_full_en(chan, num, ints, language, -1, -1));
160         }
161         /* French */
162         if (!strcasecmp(language, "fr")) {              /* French syntax */
163            return(ast_say_number_full_fr(chan, num, ints, language, -1, -1));
164         } else if (!strcasecmp(language, "da")) {       /* Danish syntax */
165            return(ast_say_number_full_da(chan, num, ints, language, options, -1, -1));
166         } else if (!strcasecmp(language, "de")) {       /* German syntax */
167            return(ast_say_number_full_de(chan, num, ints, language, -1, -1));
168         } else if (!strcasecmp(language, "it")) {       /* Italian syntax */
169            return(ast_say_number_full_it(chan, num, ints, language, -1, -1));
170         } else if (!strcasecmp(language, "pt")) {       /* Portuguese syntax */
171            return(ast_say_number_full_pt(chan, num, ints, language, options, -1, -1));
172         } else if (!strcasecmp(language, "nl")) {       /* Dutch syntax */
173            return(ast_say_number_full_nl(chan, num, ints, language, -1, -1));
174         } else if (!strcasecmp(language, "es")) {       /* Spanish syntax */
175            return(ast_say_number_full_es(chan, num, ints, language, -1, -1));
176         }
177
178         /* Default to english */
179         return(ast_say_number_full_en(chan, num, ints, language, -1, -1));
180 }
181
182 /*--- ast_say_number_full_en: English syntax */
183 /* This is the default syntax, if no other syntax defined in this file is used */
184 static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
185 {
186         int res = 0;
187         int playh = 0;
188         char fn[256] = "";
189         if (!num) 
190                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
191
192         while(!res && (num || playh)) {
193                         if (playh) {
194                                 snprintf(fn, sizeof(fn), "digits/hundred");
195                                 playh = 0;
196                         } else
197                         if (num < 20) {
198                                 snprintf(fn, sizeof(fn), "digits/%d", num);
199                                 num = 0;
200                         } else
201                         if (num < 100) {
202                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
203                                 num -= ((num / 10) * 10);
204                         } else {
205                                 if (num < 1000){
206                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
207                                         playh++;
208                                         num -= ((num / 100) * 100);
209                                 } else {
210                                         if (num < 1000000) { /* 1,000,000 */
211                                                 res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
212                                                 if (res)
213                                                         return res;
214                                                 num = num % 1000;
215                                                 snprintf(fn, sizeof(fn), "digits/thousand");
216                                         } else {
217                                                 if (num < 1000000000) { /* 1,000,000,000 */
218                                                         res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
219                                                         if (res)
220                                                                 return res;
221                                                         num = num % 1000000;
222                                                         snprintf(fn, sizeof(fn), "digits/million");
223                                                 } else {
224                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
225                                                         res = -1;
226                                                 }
227                                         }
228                                 }
229                         }
230                          if (!res) {
231                                 if(!ast_streamfile(chan, fn, language)) {
232                                     if (audiofd && ctrlfd)
233                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
234                                     else
235                                          res = ast_waitstream(chan, ints);
236                                 }
237                                 ast_stopstream(chan);
238
239                         }
240                         
241         }
242         return res;
243 }
244
245
246 /*--- ast_say_number_full_fr: French syntax */
247 static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
248 {
249         int res = 0;
250         int playh = 0;
251         int playa = 0;  /* For french */
252         char fn[256] = "";
253         if (!num) 
254                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
255            while(!res && (num || playh || playa)) {
256                        if (playh) {
257                                snprintf(fn, sizeof(fn), "digits/hundred");
258                                playh = 0;
259                        } else
260                        if (playa) {
261                                snprintf(fn, sizeof(fn), "digits/et");
262                                playa = 0;
263                        } else
264                        if (num < 21) {
265                                snprintf(fn, sizeof(fn), "digits/%d", num);
266                                num = 0;
267                        } else
268                          if (num < 70) {
269                                  snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
270                                  if ((num % 10) == 1) playa++;
271                                  num = num % 10;
272                          } else
273                          if (num < 80) {
274                                  snprintf(fn, sizeof(fn), "digits/60");
275                                  if ((num % 10) == 1) playa++;
276                                  num = num - 60;
277                          } else
278                          if (num < 100) {
279                                  snprintf(fn, sizeof(fn), "digits/80");
280                                  num = num - 80;
281                          } else
282                          if (num < 200) {
283                                  snprintf(fn, sizeof(fn), "digits/hundred");
284                                  num = num - 100;
285                          } else
286                          if (num < 1000) {
287                                  snprintf(fn, sizeof(fn), "digits/%d", (num/100));
288                                  playh++;
289                                  num = num % 100;
290                          } else
291                          if (num < 2000) {
292                                  snprintf(fn, sizeof(fn), "digits/thousand");
293                                  num = num - 1000;
294                          } else
295                          if (num < 1000000) {
296                                  res = ast_say_number_full_fr(chan, num / 1000, ints, language, audiofd, ctrlfd);
297                                  if (res) return res;
298                                  snprintf(fn, sizeof(fn), "digits/thousand");
299                                  num = num % 1000;
300                          } else
301                          if (num < 1000000000) {
302                                  res = ast_say_number_full_fr(chan, num / 1000000, ints, language, audiofd, ctrlfd);
303                                  if (res) return res;
304                                  snprintf(fn, sizeof(fn), "digits/million");
305                                  num = num % 1000000;
306                          } else {
307                                  ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
308                                  res = -1;
309                          }
310                         if (!res) {
311                                 if(!ast_streamfile(chan, fn, language)) {
312                                     if (audiofd && ctrlfd)
313                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
314                                     else
315                                          res = ast_waitstream(chan, ints);
316                                 }
317                                 ast_stopstream(chan);
318
319                         }
320
321
322         }
323         return res;
324 }
325
326 /*--- ast_say_number_full_da: Danish syntax */
327 /* New files:
328  In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and" 
329  */
330 static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
331 {
332         int res = 0;
333         int playh = 0;
334         int playa = 0;
335         int cn = 1;             /* +1 = Commune; -1 = Neutrum */
336         char fn[256] = "";
337         if (!num) 
338                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
339
340         if (options && !strncasecmp(options, "n",1)) cn = -1;
341
342         while(!res && (num || playh || playa )) {
343                /* The grammar for Danish numbers is the same as for English except
344                 * for the following:
345                 * - 1 exists in both commune ("en", file "1N") and neutrum ("et", file "1")
346                 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
347                 *   "one-and twenty" and 68 is "eight-and sixty".
348                 * - "million" is different in singular and plural form
349                 * - numbers > 1000 with zero as the third digit from last have an
350                 *   "and" before the last two digits, i.e. 2034 is "two thousand and
351                 *   four-and thirty" and 1000012 is "one million and twelve".
352                 */
353                        if (playh) {
354                                snprintf(fn, sizeof(fn), "digits/hundred");
355                                playh = 0;
356                        } else
357                        if (playa) {
358                                snprintf(fn, sizeof(fn), "digits/and");
359                                playa = 0;
360                        } else
361                        if (num == 1 && cn == -1) {
362                                 snprintf(fn, sizeof(fn), "digits/1N");
363                                 num = 0;
364                        } else
365                        if (num < 20) {
366                                snprintf(fn, sizeof(fn), "digits/%d", num);
367                                num = 0;
368                        } else
369                        if (num < 100) {
370                                int ones = num % 10;
371                                if (ones) {
372                                        snprintf(fn, sizeof(fn), "digits/%d-and", ones);
373                                        num -= ones;
374                                } else {
375                                        snprintf(fn, sizeof(fn), "digits/%d", num);
376                                        num = 0;
377                                }
378                        } else {
379                                if (num < 1000) {
380                                         int hundreds = num / 100;
381                                          if (hundreds == 1)
382                                                  snprintf(fn, sizeof(fn), "digits/1N");
383                                          else
384                                                  snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
385
386                                        playh++;
387                                        num -= 100 * hundreds;
388                                        if (num)
389                                                  playa++;
390
391                                } else {
392                                        if (num < 1000000) {
393                                                res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
394                                                if (res)
395                                                        return res;
396                                                num = num % 1000;
397                                                snprintf(fn, sizeof(fn), "digits/thousand");
398                                        } else {
399                                                if (num < 1000000000) {
400                                                        int millions = num / 1000000;
401                                                        res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
402                                                        if (res)
403                                                                return res;
404                                                        if (millions == 1)
405                                                                snprintf(fn, sizeof(fn), "digits/million");
406                                                        else
407                                                               snprintf(fn, sizeof(fn), "digits/millions");
408                                                        num = num % 1000000;
409                                         } else {
410                                                        ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
411                                                        res = -1;
412                                                }
413                                        }
414                                        if (num && num < 100)
415                                                playa++;
416                                }
417                        }
418                         if (!res) {
419                                 if(!ast_streamfile(chan, fn, language)) {
420                                     if (audiofd && ctrlfd) 
421                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
422                                     else  
423                                          res = ast_waitstream(chan, ints);
424                                 }
425                                 ast_stopstream(chan);
426         
427                         }
428                         
429         }
430         return res;
431 }
432
433 /*--- ast_say_number_full_de: German syntax */
434 /* New files:
435  In addition to English, the following sounds are required: "millions", "and" and "1-and" through "9-and" 
436  */
437 static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
438 {
439         int res = 0;
440         int playh = 0;
441         int playa = 0;
442         char fn[256] = "";
443         if (!num) 
444                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
445
446         while(!res && (num || playh || playa )) {
447                /* The grammar for German numbers is the same as for English except
448                 * for the following:
449                 * - numbers 20 through 99 are said in reverse order, i.e. 21 is
450                 *   "one-and twenty" and 68 is "eight-and sixty".
451                 * - "million" is different in singular and plural form
452                 * - numbers > 1000 with zero as the third digit from last have an
453                 *   "and" before the last two digits, i.e. 2034 is "two thousand and
454                 *   four-and thirty" and 1000012 is "one million and twelve".
455                 */
456                        if (playh) {
457                                snprintf(fn, sizeof(fn), "digits/hundred");
458                                playh = 0;
459                        } else
460                        if (playa) {
461                                snprintf(fn, sizeof(fn), "digits/and");
462                                playa = 0;
463                        } else
464                        if (num < 20) {
465                                snprintf(fn, sizeof(fn), "digits/%d", num);
466                                num = 0;
467                        } else
468                        if (num < 100) {
469                                int ones = num % 10;
470                                if (ones) {
471                                        snprintf(fn, sizeof(fn), "digits/%d-and", ones);
472                                        num -= ones;
473                                } else {
474                                        snprintf(fn, sizeof(fn), "digits/%d", num);
475                                        num = 0;
476                                }
477                        } else {
478                                if (num < 1000) {
479                                         int hundreds = num / 100;
480                                          if (hundreds == 1)
481                                                  snprintf(fn, sizeof(fn), "digits/1N");
482                                          else
483                                                  snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
484
485                                        playh++;
486                                        num -= 100 * hundreds;
487                                        if (num)
488                                                  playa++;
489
490                                } else {
491                                        if (num < 1000000) {
492                                                res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
493                                                if (res)
494                                                        return res;
495                                                num = num % 1000;
496                                                snprintf(fn, sizeof(fn), "digits/thousand");
497                                        } else {
498                                                if (num < 1000000000) {
499                                                        int millions = num / 1000000;
500                                                        res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
501                                                        if (res)
502                                                                return res;
503                                                        if (millions == 1)
504                                                                snprintf(fn, sizeof(fn), "digits/million");
505                                                        else
506                                                               snprintf(fn, sizeof(fn), "digits/millions");
507                                                        num = num % 1000000;
508                                         } else {
509                                                        ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
510                                                        res = -1;
511                                                }
512                                        }
513                                        if (num && num < 100)
514                                                playa++;
515                                }
516                        }
517                         if (!res) {
518                                 if(!ast_streamfile(chan, fn, language)) {
519                                     if (audiofd && ctrlfd) 
520                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
521                                     else  
522                                          res = ast_waitstream(chan, ints);
523                                 }
524                                 ast_stopstream(chan);
525         
526                         }
527                         
528         }
529         return res;
530 }
531
532 /*------------ Portuguese ----------------------*/
533 /* ast_say_number_full_pt: Portuguese syntax */
534 /*      Extra sounds needed: */
535 /*      For feminin all sound files end with F */
536 /*      100E for 100+ something */
537 /*      1000000S for plural */
538 /*      pt-e for 'and' */
539 static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
540 {
541         int res = 0;
542         int playh = 0;
543         int mf = 1;                            /* +1 = Masculin; -1 = Feminin */
544
545         char fn[256] = "";
546
547         if (!num) 
548                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
549
550         if (options && !strncasecmp(options, "f",1)) mf = -1;
551
552          while(!res && num ) {
553
554                         if (num < 20) {
555                                  if ((num == 1 || num == 2) && (mf < 0))
556                                      snprintf(fn, sizeof(fn), "digits/%dF", num);
557                                  else
558                                      snprintf(fn, sizeof(fn), "digits/%d", num);
559                                  num = 0;
560                          } else
561                          if (num < 100) {
562                                  snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
563                                  if (num % 10)
564                                      playh = 1;
565                                  num = num % 10;
566                          } else
567                          if (num < 1000) {
568                                  if (num == 100)
569                                      snprintf(fn, sizeof(fn), "digits/100");
570                                  else if (num < 200)
571                                      snprintf(fn, sizeof(fn), "digits/100E");
572                                  else {
573                                      if (mf < 0 && num > 199)
574                                          snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
575                                      else
576                                          snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
577                                      if (num % 100)
578                                          playh = 1;
579                                  }
580                                  num = num % 100;
581                          } else
582                          if (num < 1000000) {
583                                  if (num > 1999) {
584                                     res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
585                                     if (res)
586                                          return res;
587                                  }
588                                  snprintf(fn, sizeof(fn), "digits/1000");
589                                  if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
590                                      playh = 1;
591                                  num = num % 1000;
592                          } else
593                          if (num < 1000000000) {
594                                 res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
595                                 if (res)
596                                      return res;
597  
598                                  if (num < 2000000)
599                                      snprintf(fn, sizeof(fn), "digits/1000000");
600                                  else
601                                      snprintf(fn, sizeof(fn), "digits/1000000S");
602  
603                                  if ((num % 1000000) &&
604                                    // no thousands
605                                    ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
606                                    // no hundreds and below
607                                    (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
608                                          playh = 1;
609                                  num = num % 1000000;
610                          }
611                         if (!res && playh) {
612                                 res = wait_file(chan, ints, "digits/pt-e", language);
613                                 ast_stopstream(chan);
614                                 playh = 0;
615                         }
616                         if (!res) {
617                                 if(!ast_streamfile(chan, fn, language)) {
618                                     if (audiofd && ctrlfd)
619                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
620                                     else
621                                          res = ast_waitstream(chan, ints);
622                                 }
623                                 ast_stopstream(chan);
624
625                         }
626
627         }
628         return res;
629 }
630
631
632 /*--- ast_say_number_full_it:  italian */
633 static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
634 {
635         int res = 0;
636         int playh = 0;
637         int tempnum = 0;
638         char fn[256] = "";
639
640         if (!num)
641                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
642
643                 /*
644                 Italian support
645
646                 Like english, numbers till 20 are a single 'word', and other
647                 compound, but with exceptions.
648                 For example 21 is not twenty-one, but is a single word in it.
649                 Idem for 28 (ie when a the 2nd part of a compund number
650                 starts with a wovel)
651
652                 There're exceptions also for hundred, thounsand and million.
653                 In english 100 = one hundred, 200 is two hundred.
654                 In italian 100 = cento , like to say hundred (without one),
655                 200 and more are like english.
656                 
657                 Same apply for thousand:
658                 1000 is one thousand in en, 2000 is two thousand.
659                 In it we have 1000 = mille , 2000 = 2 mila 
660
661                 For million(s) we use the plural, if more than one
662                 Also, one million is abbreviated in it, like on-million,
663                 or 'un milione', not 'uno milione'.
664                 So the right file is provided.
665                 */
666
667                 while(!res && (num || playh)) {
668                         if (playh) {
669                                 snprintf(fn, sizeof(fn), "digits/hundred");
670                                 playh = 0;
671                         } else
672                         if (num < 20) {
673                                 snprintf(fn, sizeof(fn), "digits/%d", num);
674                                 num = 0;
675                         } else
676                         if (num == 21) {
677                                 snprintf(fn, sizeof(fn), "digits/%d", num);
678                                 num = 0;
679                         } else
680                         if (num == 28) {
681                                 snprintf(fn, sizeof(fn), "digits/%d", num);
682                                 num = 0;
683                         } else
684                         if (num == 31) {
685                                 snprintf(fn, sizeof(fn), "digits/%d", num);
686                                 num = 0;
687                         } else
688                         if (num == 38) {
689                                 snprintf(fn, sizeof(fn), "digits/%d", num);
690                                 num = 0;
691                         } else
692                         if (num == 41) {
693                                 snprintf(fn, sizeof(fn), "digits/%d", num);
694                                 num = 0;
695                         } else
696                         if (num == 48) {
697                                 snprintf(fn, sizeof(fn), "digits/%d", num);
698                                 num = 0;
699                         } else
700                         if (num == 51) {
701                                 snprintf(fn, sizeof(fn), "digits/%d", num);
702                                 num = 0;
703                         } else
704                         if (num == 58) {
705                                 snprintf(fn, sizeof(fn), "digits/%d", num);
706                                 num = 0;
707                         } else
708                         if (num == 61) {
709                                 snprintf(fn, sizeof(fn), "digits/%d", num);
710                                 num = 0;
711                         } else
712                         if (num == 68) {
713                                 snprintf(fn, sizeof(fn), "digits/%d", num);
714                                 num = 0;
715                         } else
716                         if (num == 71) {
717                                 snprintf(fn, sizeof(fn), "digits/%d", num);
718                                 num = 0;
719                         } else
720                         if (num == 78) {
721                                 snprintf(fn, sizeof(fn), "digits/%d", num);
722                                 num = 0;
723                         } else
724                         if (num == 81) {
725                                 snprintf(fn, sizeof(fn), "digits/%d", num);
726                                 num = 0;
727                         } else
728                         if (num == 88) {
729                                 snprintf(fn, sizeof(fn), "digits/%d", num);
730                                 num = 0;
731                         } else
732                         if (num == 91) {
733                                 snprintf(fn, sizeof(fn), "digits/%d", num);
734                                 num = 0;
735                         } else
736                         if (num == 98) {
737                                 snprintf(fn, sizeof(fn), "digits/%d", num);
738                                 num = 0;
739                         } else
740                         if (num < 100) {
741                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
742                                 num -= ((num / 10) * 10);
743                         } else {
744                                 if (num < 1000){
745                                         if ((num / 100) > 1) {
746                                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
747                                                 playh++;
748                                         }
749                                         else {
750                                                 snprintf(fn, sizeof(fn), "digits/hundred");
751                                         }
752                                         num -= ((num / 100) * 100);
753                                 } else {
754                                         if (num < 1000000) { /* 1,000,000 */
755                                                 if ((num/1000) > 1)
756                                                         res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd);
757                                                 if (res)
758                                                         return res;
759                                                 tempnum = num;
760                                                 num = num % 1000;
761                                                 if ((tempnum / 1000) < 2)
762                                                         snprintf(fn, sizeof(fn), "digits/thousand");
763                                                 else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
764                                                         snprintf(fn, sizeof(fn), "digits/thousands");
765                                         } else {
766                                                 if (num < 1000000000) { /* 1,000,000,000 */
767                                                         if ((num / 1000000) > 1)
768                                                                 res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd);
769                                                         if (res)
770                                                                 return res;
771                                                         tempnum = num;
772                                                         num = num % 1000000;
773                                                         if ((tempnum / 1000000) < 2)
774                                                                 snprintf(fn, sizeof(fn), "digits/million");
775                                                         else
776                                                                 snprintf(fn, sizeof(fn), "digits/millions");
777                                                 } else {
778                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
779                                                         res = -1;
780                                                 }
781                                         }
782                                 }
783                         }
784                          if (!res) {
785                                 if(!ast_streamfile(chan, fn, language)) {
786                                     if (audiofd && ctrlfd)
787                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
788                                     else
789                                          res = ast_waitstream(chan, ints);
790                                 }
791                                 ast_stopstream(chan);
792
793                         }
794                 }
795         return res;
796 }
797  
798
799 /*--- ast_say_number_full_es: spanish syntax */
800 /* New files:
801  Requires a few new audios:
802    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 
803  */
804 static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
805 {
806         int res = 0;
807         int playa = 0;
808         char fn[256] = "";
809         if (!num) 
810                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
811         while (!res && num) {
812                                 if (playa) {
813                                         snprintf(fn, sizeof(fn), "digits/y");
814                                         playa = 0;
815                                 } else 
816                                 if (num < 31) {
817                                         snprintf(fn, sizeof(fn), "digits/%d", num);
818                                         num = 0;
819                                 } else  
820                                 if (num < 100) {
821                                         snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
822                                         num -= ((num/10)*10);
823                                         if (num)
824                                                 playa++;
825                                 } else
826                                 if (num == 100) {
827                                         snprintf(fn, sizeof(fn), "digits/cien");
828                                         num = 0;
829                                 } else {
830                                         if (num < 1000) {
831                                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
832                                                 num -= ((num/100)*100);
833                                         } else {
834                                                 if (num < 1000000) {
835                                                         res = ast_say_number_full_es(chan, num / 1000, ints, language, audiofd, ctrlfd);
836                                                         if (res)
837                                                                 return res;
838                                                         num = num % 1000;
839                                                         snprintf(fn, sizeof(fn), "digits/mil");
840                                                 } else {
841                                                         if (num < 2147483640) {
842                                                                 res = ast_say_number_full_es(chan, num / 1000000, ints, language, audiofd, ctrlfd);
843                                                                 if (res)
844                                                                         return res;
845                                                                 if ((num/1000000) == 1) {
846                                                                         snprintf(fn, sizeof(fn), "digits/millon");
847                                                                 } else {
848                                                                         snprintf(fn, sizeof(fn), "digits/millones");
849                                                                 }
850                                                                 num = num % 1000000;
851                                                         } else {
852                                                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
853                                                                 res = -1;
854                                                         }
855                                                 }
856                                         }
857                                 }
858
859                          if (!res) {
860                                 if(!ast_streamfile(chan, fn, language)) {
861                                     if (audiofd && ctrlfd)
862                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
863                                     else
864                                          res = ast_waitstream(chan, ints);
865                                 }
866                                 ast_stopstream(chan);
867
868                         }
869                         
870         }
871         return res;
872 }
873
874 /*--- ast_say_number_full_nl: dutch syntax */
875 /* New files: ???
876  */
877 static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
878 {
879         int res = 0;
880         int playh = 0;
881         int units = 0;
882         char fn[256] = "";
883         if (!num) 
884                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
885         while (!res && (num || playh )) {
886                  if (playh) {
887                      snprintf(fn, sizeof(fn), "digits/hundred");
888                      playh = 0;
889                  } else
890                  if (num < 20) {
891                      snprintf(fn, sizeof(fn), "digits/%d", num);
892                      num = 0;
893                  } else
894                  if (num < 100) {
895                      units = num % 10;
896                      if (units > 0) {
897                         res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
898                         if (res)
899                             return res;
900                         num = num - units;
901                         snprintf(fn, sizeof(fn), "digits/nl-en");
902                      } else {
903                         snprintf(fn, sizeof(fn), "digits/%d", num - units);
904                         num = 0;
905                      }
906                  } else {
907                      if (num < 1000){
908                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
909                         playh++;
910                         num -= ((num / 100) * 100);
911                      } else {
912                         if (num < 1000000) { /* 1,000,000 */
913                            res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
914                            if (res)
915                               return res;
916                            num = num % 1000;
917                            snprintf(fn, sizeof(fn), "digits/thousand");
918                        } else {
919                          if (num < 1000000000) { /* 1,000,000,000 */
920                             res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
921                             if (res)
922                                return res;
923                             num = num % 1000000;
924                             snprintf(fn, sizeof(fn), "digits/million");
925                          } else {
926                             ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
927                             res = -1;
928                          }
929                       } 
930                    }
931                 }
932
933                 if (!res) {
934                    if(!ast_streamfile(chan, fn, language)) {
935                        if (audiofd && ctrlfd)
936                           res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
937                        else
938                           res = ast_waitstream(chan, ints);
939                    }
940                    ast_stopstream(chan);
941
942               }
943                         
944         }
945         return res;
946 }
947
948
949 int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
950 {
951         struct tm tm;
952         char fn[256];
953         int res = 0;
954         ast_localtime(&t,&tm,NULL);
955         if (!res) {
956                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
957                 res = ast_streamfile(chan, fn, lang);
958                 if (!res)
959                         res = ast_waitstream(chan, ints);
960         }
961         if (!res) {
962                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
963                 res = ast_streamfile(chan, fn, lang);
964                 if (!res)
965                         res = ast_waitstream(chan, ints);
966         }
967         if (!res)
968                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
969                 /* Should portuguese add a gender here?  Defaults to masculin */
970
971         if (!res)
972                 res = ast_waitstream(chan, ints);
973         if (!res)
974                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
975         return res;
976 }
977
978 static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang) 
979 {
980         int res;
981         if ((res = ast_streamfile(chan, file, lang)))
982                 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
983         if (!res)
984                 res = ast_waitstream(chan, ints);
985         return res;
986 }
987
988 int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
989 {
990         struct tm tm;
991         int res=0, offset, sndoffset;
992         char sndfile[256], nextmsg[256];
993
994         ast_localtime(&time,&tm,timezone);
995
996         for (offset=0 ; format[offset] != '\0' ; offset++) {
997                 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
998                 switch (format[offset]) {
999                         /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
1000                         case '\'':
1001                                 /* Literal name of a sound file */
1002                                 sndoffset=0;
1003                                 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
1004                                         sndfile[sndoffset] = format[offset];
1005                                 sndfile[sndoffset] = '\0';
1006                                 snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile);
1007                                 res = wait_file(chan,ints,nextmsg,lang);
1008                                 break;
1009                         case 'A':
1010                         case 'a':
1011                                 /* Sunday - Saturday */
1012                                 snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
1013                                 res = wait_file(chan,ints,nextmsg,lang);
1014                                 break;
1015                         case 'B':
1016                         case 'b':
1017                         case 'h':
1018                                 /* January - December */
1019                                 snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
1020                                 res = wait_file(chan,ints,nextmsg,lang);
1021                                 break;
1022                         case 'd':
1023                         case 'e':
1024                                 /* First - Thirtyfirst */
1025                                 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) {
1026                                         snprintf(nextmsg,sizeof(nextmsg), "digits/h-%d", tm.tm_mday);
1027                                         res = wait_file(chan,ints,nextmsg,lang);
1028                                 } else if (tm.tm_mday == 31) {
1029                                         /* "Thirty" and "first" */
1030                                         res = wait_file(chan,ints, "digits/30",lang);
1031                                         if (!res) {
1032                                                 res = wait_file(chan,ints, "digits/h-1",lang);
1033                                         }
1034                                 } else {
1035                                         /* Between 21 and 29 - two sounds */
1036                                         res = wait_file(chan,ints, "digits/20",lang);
1037                                         if (!res) {
1038                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_mday - 20);
1039                                                 res = wait_file(chan,ints,nextmsg,lang);
1040                                         }
1041                                 }
1042                                 break;
1043                         case 'Y':
1044                                 /* Year */
1045                                 if (tm.tm_year > 99) {
1046                                         res = wait_file(chan,ints, "digits/2",lang);
1047                                         if (!res) {
1048                                                 res = wait_file(chan,ints, "digits/thousand",lang);
1049                                         }
1050                                         if (tm.tm_year > 100) {
1051                                                 if (!res) {
1052                                                         /* This works until the end of 2020 */
1053                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
1054                                                         res = wait_file(chan,ints,nextmsg,lang);
1055                                                 }
1056                                         }
1057                                 } else {
1058                                         if (tm.tm_year < 1) {
1059                                                 /* I'm not going to handle 1900 and prior */
1060                                                 /* We'll just be silent on the year, instead of bombing out. */
1061                                         } else {
1062                                                 res = wait_file(chan,ints, "digits/19",lang);
1063                                                 if (!res) {
1064                                                         if (tm.tm_year <= 9) {
1065                                                                 /* 1901 - 1909 */
1066                                                                 res = wait_file(chan,ints, "digits/oh",lang);
1067                                                                 if (!res) {
1068                                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
1069                                                                         res = wait_file(chan,ints,nextmsg,lang);
1070                                                                 }
1071                                                         } else if (tm.tm_year <= 20) {
1072                                                                 /* 1910 - 1920 */
1073                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
1074                                                                 res = wait_file(chan,ints,nextmsg,lang);
1075                                                         } else {
1076                                                                 /* 1921 - 1999 */
1077                                                                 int ten, one;
1078                                                                 ten = tm.tm_year / 10;
1079                                                                 one = tm.tm_year % 10;
1080                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
1081                                                                 res = wait_file(chan,ints,nextmsg,lang);
1082                                                                 if (!res) {
1083                                                                         if (one != 0) {
1084                                                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
1085                                                                                 res = wait_file(chan,ints,nextmsg,lang);
1086                                                                         }
1087                                                                 }
1088                                                         }
1089                                                 }
1090                                         }
1091                                 }
1092                                 break;
1093                         case 'I':
1094                         case 'l':
1095                                 /* 12-Hour */
1096                                 if (tm.tm_hour == 0)
1097                                         snprintf(nextmsg,sizeof(nextmsg), "digits/12");
1098                                 else if (tm.tm_hour > 12)
1099                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
1100                                 else
1101                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
1102                                 res = wait_file(chan,ints,nextmsg,lang);
1103                                 break;
1104                         case 'H':
1105                         case 'k':
1106                                 /* 24-Hour */
1107                                 if (format[offset] == 'H') {
1108                                         /* e.g. oh-eight */
1109                                         if (tm.tm_hour < 10) {
1110                                                 res = wait_file(chan,ints, "digits/oh",lang);
1111                                         }
1112                                 } else {
1113                                         /* e.g. eight */
1114                                         if (tm.tm_hour == 0) {
1115                                                 res = wait_file(chan,ints, "digits/oh",lang);
1116                                         }
1117                                 }
1118                                 if (!res) {
1119                                         if (tm.tm_hour != 0) {
1120                                                 int remainder = tm.tm_hour;
1121                                                 if (tm.tm_hour > 20) {
1122                                                         res = wait_file(chan,ints, "digits/20",lang);
1123                                                         remainder -= 20;
1124                                                 }
1125                                                 if (!res) {
1126                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
1127                                                         res = wait_file(chan,ints,nextmsg,lang);
1128                                                 }
1129                                         }
1130                                 }
1131                                 break;
1132                         case 'M':
1133                                 /* Minute */
1134                                 if (tm.tm_min == 0) {
1135                                         res = wait_file(chan,ints, "digits/oclock",lang);
1136                                 } else if (tm.tm_min < 10) {
1137                                         res = wait_file(chan,ints, "digits/oh",lang);
1138                                         if (!res) {
1139                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
1140                                                 res = wait_file(chan,ints,nextmsg,lang);
1141                                         }
1142                                 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
1143                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
1144                                         res = wait_file(chan,ints,nextmsg,lang);
1145                                 } else {
1146                                         int ten, one;
1147                                         ten = (tm.tm_min / 10) * 10;
1148                                         one = (tm.tm_min % 10);
1149                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
1150                                         res = wait_file(chan,ints,nextmsg,lang);
1151                                         if (!res) {
1152                                                 /* Fifty, not fifty-zero */
1153                                                 if (one != 0) {
1154                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
1155                                                         res = wait_file(chan,ints,nextmsg,lang);
1156                                                 }
1157                                         }
1158                                 }
1159                                 break;
1160                         case 'P':
1161                         case 'p':
1162                                 /* AM/PM */
1163                                 if (tm.tm_hour > 11)
1164                                         snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
1165                                 else
1166                                         snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
1167                                 res = wait_file(chan,ints,nextmsg,lang);
1168                                 break;
1169                         case 'Q':
1170                                 /* Shorthand for "Today", "Yesterday", or ABdY */
1171                                 {
1172                                         struct timeval now;
1173                                         struct tm tmnow;
1174                                         time_t beg_today;
1175
1176                                         gettimeofday(&now,NULL);
1177                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
1178                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
1179                                         /* In any case, it saves not having to do ast_mktime() */
1180                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
1181                                         if (beg_today < time) {
1182                                                 /* Today */
1183                                                 res = wait_file(chan,ints, "digits/today",lang);
1184                                         } else if (beg_today - 86400 < time) {
1185                                                 /* Yesterday */
1186                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
1187                                         } else {
1188                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
1189                                         }
1190                                 }
1191                                 break;
1192                         case 'q':
1193                                 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
1194                                 {
1195                                         struct timeval now;
1196                                         struct tm tmnow;
1197                                         time_t beg_today;
1198
1199                                         gettimeofday(&now,NULL);
1200                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
1201                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
1202                                         /* In any case, it saves not having to do ast_mktime() */
1203                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
1204                                         if (beg_today < time) {
1205                                                 /* Today */
1206                                         } else if ((beg_today - 86400) < time) {
1207                                                 /* Yesterday */
1208                                                 res = wait_file(chan,ints, "digits/yesterday",lang);
1209                                         } else if (beg_today - 86400 * 6 < time) {
1210                                                 /* Within the last week */
1211                                                 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
1212                                         } else {
1213                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
1214                                         }
1215                                 }
1216                                 break;
1217                         case 'R':
1218                                 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
1219                                 break;
1220                         case 'S':
1221                                 /* Seconds */
1222                                 if (tm.tm_sec == 0) {
1223                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
1224                                         res = wait_file(chan,ints,nextmsg,lang);
1225                                 } else if (tm.tm_sec < 10) {
1226                                         res = wait_file(chan,ints, "digits/oh",lang);
1227                                         if (!res) {
1228                                                 snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
1229                                                 res = wait_file(chan,ints,nextmsg,lang);
1230                                         }
1231                                 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
1232                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
1233                                         res = wait_file(chan,ints,nextmsg,lang);
1234                                 } else {
1235                                         int ten, one;
1236                                         ten = (tm.tm_sec / 10) * 10;
1237                                         one = (tm.tm_sec % 10);
1238                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
1239                                         res = wait_file(chan,ints,nextmsg,lang);
1240                                         if (!res) {
1241                                                 /* Fifty, not fifty-zero */
1242                                                 if (one != 0) {
1243                                                         snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
1244                                                         res = wait_file(chan,ints,nextmsg,lang);
1245                                                 }
1246                                         }
1247                                 }
1248                                 break;
1249                         case 'T':
1250                                 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
1251                                 break;
1252                         case ' ':
1253                         case '  ':
1254                                 /* Just ignore spaces and tabs */
1255                                 break;
1256                         default:
1257                                 /* Unknown character */
1258                                 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
1259                 }
1260                 /* Jump out on DTMF */
1261                 if (res) {
1262                         break;
1263                 }
1264         }
1265         return res;
1266 }
1267
1268 int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang)
1269 {
1270         struct tm tm;
1271         int res = 0;
1272         int hour, pm=0;
1273         localtime_r(&t,&tm);
1274         hour = tm.tm_hour;
1275         if (!hour)
1276                 hour = 12;
1277         else if (hour == 12)
1278                 pm = 1;
1279         else if (hour > 12) {
1280                 hour -= 12;
1281                 pm = 1;
1282         }
1283         if (!res)
1284                 res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
1285
1286         if (tm.tm_min > 9) {
1287                 if (!res)
1288                         res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
1289         } else if (tm.tm_min) {
1290                 if (!res)
1291                         res = ast_streamfile(chan, "digits/oh", lang);  /* This is very english ! */
1292                 if (!res)
1293                         res = ast_waitstream(chan, ints);
1294                 if (!res)
1295                         res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
1296         } else {
1297                 if (!res)
1298                         res = ast_streamfile(chan, "digits/oclock", lang);      /* This is very english ! */
1299                 if (!res)
1300                         res = ast_waitstream(chan, ints);
1301         }
1302         if (pm) {
1303                 if (!res)
1304                         res = ast_streamfile(chan, "digits/p-m", lang);
1305         } else {
1306                 if (!res)
1307                         res = ast_streamfile(chan, "digits/a-m", lang);
1308         }
1309         if (!res)
1310                 res = ast_waitstream(chan, ints);
1311         return res;
1312 }
1313
1314 int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang)
1315 {
1316         struct tm tm;
1317         char fn[256];
1318         int res = 0;
1319         int hour, pm=0;
1320         localtime_r(&t,&tm);
1321         if (!res) {
1322                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
1323                 res = ast_streamfile(chan, fn, lang);
1324                 if (!res)
1325                         res = ast_waitstream(chan, ints);
1326         }
1327         if (!res) {
1328                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
1329                 res = ast_streamfile(chan, fn, lang);
1330                 if (!res)
1331                         res = ast_waitstream(chan, ints);
1332         }
1333         if (!res)
1334                 res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
1335
1336         hour = tm.tm_hour;
1337         if (!hour)
1338                 hour = 12;
1339         else if (hour == 12)
1340                 pm = 1;
1341         else if (hour > 12) {
1342                 hour -= 12;
1343                 pm = 1;
1344         }
1345         if (!res)
1346                 res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
1347
1348         if (tm.tm_min > 9) {
1349                 if (!res)
1350                         res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
1351         } else if (tm.tm_min) {
1352                 if (!res)
1353                         res = ast_streamfile(chan, "digits/oh", lang);
1354                 if (!res)
1355                         res = ast_waitstream(chan, ints);
1356                 if (!res)
1357                         res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
1358         } else {
1359                 if (!res)
1360                         res = ast_streamfile(chan, "digits/oclock", lang);
1361                 if (!res)
1362                         res = ast_waitstream(chan, ints);
1363         }
1364         if (pm) {
1365                 if (!res)
1366                         res = ast_streamfile(chan, "digits/p-m", lang);
1367         } else {
1368                 if (!res)
1369                         res = ast_streamfile(chan, "digits/a-m", lang);
1370         }
1371         if (!res)
1372                 res = ast_waitstream(chan, ints);
1373         if (!res)
1374                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
1375         return res;
1376 }
1377
1378 int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang)
1379 {
1380         int res=0;
1381         time_t nowt;
1382         int daydiff;
1383         struct tm tm;
1384         struct tm now;
1385         char fn[256];
1386
1387         time(&nowt);
1388
1389         localtime_r(&t,&tm);
1390         localtime_r(&nowt,&now);
1391         daydiff = now.tm_yday - tm.tm_yday;
1392         if ((daydiff < 0) || (daydiff > 6)) {
1393                 /* Day of month and month */
1394                 if (!res) {
1395                         snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
1396                         res = ast_streamfile(chan, fn, lang);
1397                         if (!res)
1398                                 res = ast_waitstream(chan, ints);
1399                 }
1400                 if (!res)
1401                         res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
1402
1403         } else if (daydiff) {
1404                 /* Just what day of the week */
1405                 if (!res) {
1406                         snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
1407                         res = ast_streamfile(chan, fn, lang);
1408                         if (!res)
1409                                 res = ast_waitstream(chan, ints);
1410                 }
1411         } /* Otherwise, it was today */
1412         if (!res)
1413                 res = ast_say_time(chan, t, ints, lang);
1414         return res;
1415 }
1416