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