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