2ca660500d49349cd3915119b06fb049d20f138c
[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 #define DIGITS_DIR      AST_SOUNDS "/digits/"
29
30 int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
31 {
32         /* XXX Merge with full version? XXX */
33         char fn[256] = "";
34         int num = 0;
35         int res = 0;
36         while(fn2[num] && !res) {
37                 switch (fn2[num]) {
38                         case ('*'):
39                                 snprintf(fn, sizeof(fn), "digits/star");
40                                 break;
41                         case ('#'):
42                                 snprintf(fn, sizeof(fn), "digits/pound");
43                                 break;
44                         default:
45                                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
46                         }
47                 res = ast_streamfile(chan, fn, lang);
48                 if (!res) 
49                         res = ast_waitstream(chan, ints);
50                 ast_stopstream(chan);
51                 num++;
52         }
53         return res;
54 }
55
56 int ast_say_digit_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd)
57 {
58         char fn[256] = "";
59         int num = 0;
60         int res = 0;
61         while(fn2[num] && !res) {
62                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
63                 res = ast_streamfile(chan, fn, lang);
64                 if (!res) 
65                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
66                 ast_stopstream(chan);
67                 num++;
68         }
69         return res;
70 }
71
72 int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang)
73 {
74         /* XXX Should I be merged with say_digits_full XXX */
75         char fn2[256];
76         snprintf(fn2, sizeof(fn2), "%d", num);
77         return ast_say_digit_str(chan, fn2, ints, lang);
78 }
79
80 int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd)
81 {
82         char fn2[256];
83         snprintf(fn2, sizeof(fn2), "%d", num);
84         return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
85 }
86
87 int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
88 {
89         int res = 0;
90         int playh = 0;
91         char fn[256] = "";
92         if (!num) 
93                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
94         if (0) {
95         /* XXX Only works for english XXX */
96         } else {
97                 /* Use english numbers if a given language is supported. */
98                 /* As a special case, Norwegian has the same numerical grammar
99                    as English */
100                 if (strcasecmp(language, "no"))
101                         language = "en";
102                 while(!res && (num || playh)) {
103                         if (playh) {
104                                 snprintf(fn, sizeof(fn), "digits/hundred");
105                                 playh = 0;
106                         } else
107                         if (num < 20) {
108                                 snprintf(fn, sizeof(fn), "digits/%d", num);
109                                 num = 0;
110                         } else
111                         if (num < 100) {
112                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
113                                 num -= ((num / 10) * 10);
114                         } else {
115                                 if (num < 1000){
116                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
117                                         playh++;
118                                         num -= ((num / 100) * 100);
119                                 } else {
120                                         if (num < 1000000) { /* 1,000,000 */
121                                                 res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd);
122                                                 if (res)
123                                                         return res;
124                                                 num = num % 1000;
125                                                 snprintf(fn, sizeof(fn), "digits/thousand");
126                                         } else {
127                                                 if (num < 1000000000) { /* 1,000,000,000 */
128                                                         res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd);
129                                                         if (res)
130                                                                 return res;
131                                                         num = num % 1000000;
132                                                         snprintf(fn, sizeof(fn), "digits/million");
133                                                 } else {
134                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
135                                                         res = -1;
136                                                 }
137                                         }
138                                 }
139                         }
140                         if (!res) {
141                                 res = ast_streamfile(chan, fn, language);
142                                 if (!res) 
143                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
144                                 ast_stopstream(chan);
145                         }
146                         
147                 }
148         }
149         return res;
150 }
151
152 int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language)
153 {
154         /* XXX Should I be merged with ast_say_number_full XXX */
155         int res = 0;
156         int playh = 0;
157         char fn[256] = "";
158         if (!num) 
159                 return ast_say_digits(chan, 0,ints, language);
160         if (0) {
161         /* XXX Only works for english XXX */
162         } else {
163                 /* Use english numbers */
164                 language = "en";
165                 while(!res && (num || playh)) {
166                         if (playh) {
167                                 snprintf(fn, sizeof(fn), "digits/hundred");
168                                 playh = 0;
169                         } else
170                         if (num < 20) {
171                                 snprintf(fn, sizeof(fn), "digits/%d", num);
172                                 num = 0;
173                         } else
174                         if (num < 100) {
175                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
176                                 num -= ((num / 10) * 10);
177                         } else {
178                                 if (num < 1000){
179                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
180                                         playh++;
181                                         num -= ((num / 100) * 100);
182                                 } else {
183                                         if (num < 1000000) {
184                                                 res = ast_say_number(chan, num / 1000, ints, language);
185                                                 if (res)
186                                                         return res;
187                                                 num = num % 1000;
188                                                 snprintf(fn, sizeof(fn), "digits/thousand");
189                                         } else {
190                                                 if (num < 1000000000) {
191                                                         res = ast_say_number(chan, num / 1000000, ints, language);
192                                                         if (res)
193                                                                 return res;
194                                                         num = num % 1000000;
195                                                         snprintf(fn, sizeof(fn), "digits/million");
196                                                 } else {
197                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
198                                                         res = -1;
199                                                 }
200                                         }
201                                 }
202                         }
203                         if (!res) {
204                                 res = ast_streamfile(chan, fn, language);
205                                 if (!res) 
206                                         res = ast_waitstream(chan, ints);
207                                 ast_stopstream(chan);
208                         }
209                         
210                 }
211         }
212         return res;
213 }
214 int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
215 {
216         struct tm tm;
217         char fn[256];
218         int res = 0;
219         ast_localtime(&t,&tm,NULL);
220         if (!res) {
221                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
222                 res = ast_streamfile(chan, fn, lang);
223                 if (!res)
224                         res = ast_waitstream(chan, ints);
225         }
226         if (!res) {
227                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
228                 res = ast_streamfile(chan, fn, lang);
229                 if (!res)
230                         res = ast_waitstream(chan, ints);
231         }
232         if (!res)
233                 res = ast_say_number(chan, tm.tm_mday, ints, lang);
234
235         if (!res)
236                 res = ast_waitstream(chan, ints);
237         if (!res)
238                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang);
239         return res;
240 }
241
242 static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang) 
243 {
244         int res;
245         if ((res = ast_streamfile(chan, file, lang)))
246                 ast_log(LOG_WARNING, "Unable to play message %s\n", file);
247         if (!res)
248                 res = ast_waitstream(chan, ints);
249         return res;
250 }
251
252 int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
253 {
254         struct tm tm;
255         int res=0, offset, sndoffset;
256         char sndfile[256], nextmsg[256];
257
258         ast_localtime(&time,&tm,timezone);
259
260         for (offset=0 ; format[offset] != '\0' ; offset++) {
261                 ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
262                 switch (format[offset]) {
263                         /* NOTE:  if you add more options here, please try to be consistent with strftime(3) */
264                         case '\'':
265                                 /* Literal name of a sound file */
266                                 sndoffset=0;
267                                 for (sndoffset=0 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
268                                         sndfile[sndoffset] = format[offset];
269                                 sndfile[sndoffset] = '\0';
270                                 snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile);
271                                 res = wait_file(chan,ints,nextmsg,lang);
272                                 break;
273                         case 'A':
274                         case 'a':
275                                 /* Sunday - Saturday */
276                                 snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "day-%d", tm.tm_wday);
277                                 res = wait_file(chan,ints,nextmsg,lang);
278                                 break;
279                         case 'B':
280                         case 'b':
281                         case 'h':
282                                 /* January - December */
283                                 snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "mon-%d", tm.tm_mon);
284                                 res = wait_file(chan,ints,nextmsg,lang);
285                                 break;
286                         case 'd':
287                         case 'e':
288                                 /* First - Thirtyfirst */
289                                 if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) {
290                                         snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "h-%d", tm.tm_mday);
291                                         res = wait_file(chan,ints,nextmsg,lang);
292                                 } else if (tm.tm_mday == 31) {
293                                         /* "Thirty" and "first" */
294                                         res = wait_file(chan,ints,DIGITS_DIR "30",lang);
295                                         if (!res) {
296                                                 res = wait_file(chan,ints,DIGITS_DIR "h-1",lang);
297                                         }
298                                 } else {
299                                         /* Between 21 and 29 - two sounds */
300                                         res = wait_file(chan,ints,DIGITS_DIR "20",lang);
301                                         if (!res) {
302                                                 snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "h-%d", tm.tm_mday - 20);
303                                                 res = wait_file(chan,ints,nextmsg,lang);
304                                         }
305                                 }
306                                 break;
307                         case 'Y':
308                                 /* Year */
309                                 if (tm.tm_year > 99) {
310                                         res = wait_file(chan,ints,DIGITS_DIR "2",lang);
311                                         if (!res) {
312                                                 res = wait_file(chan,ints,DIGITS_DIR "thousand",lang);
313                                         }
314                                         if (tm.tm_year > 100) {
315                                                 if (!res) {
316                                                         /* This works until the end of 2020 */
317                                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year - 100);
318                                                         res = wait_file(chan,ints,nextmsg,lang);
319                                                 }
320                                         }
321                                 } else {
322                                         if (tm.tm_year < 1) {
323                                                 /* I'm not going to handle 1900 and prior */
324                                                 /* We'll just be silent on the year, instead of bombing out. */
325                                         } else {
326                                                 res = wait_file(chan,ints,DIGITS_DIR "19",lang);
327                                                 if (!res) {
328                                                         if (tm.tm_year <= 9) {
329                                                                 /* 1901 - 1909 */
330                                                                 res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
331                                                                 if (!res) {
332                                                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year);
333                                                                         res = wait_file(chan,ints,nextmsg,lang);
334                                                                 }
335                                                         } else if (tm.tm_year <= 20) {
336                                                                 /* 1910 - 1920 */
337                                                                 snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year);
338                                                                 res = wait_file(chan,ints,nextmsg,lang);
339                                                         } else {
340                                                                 /* 1921 - 1999 */
341                                                                 int ten, one;
342                                                                 ten = tm.tm_year / 10;
343                                                                 one = tm.tm_year % 10;
344                                                                 snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten * 10);
345                                                                 res = wait_file(chan,ints,nextmsg,lang);
346                                                                 if (!res) {
347                                                                         if (one != 0) {
348                                                                                 snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one);
349                                                                                 res = wait_file(chan,ints,nextmsg,lang);
350                                                                         }
351                                                                 }
352                                                         }
353                                                 }
354                                         }
355                                 }
356                                 break;
357                         case 'I':
358                         case 'l':
359                                 /* 12-Hour */
360                                 if (tm.tm_hour == 0)
361                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "12");
362                                 else if (tm.tm_hour > 12)
363                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_hour - 12);
364                                 else
365                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_hour);
366                                 res = wait_file(chan,ints,nextmsg,lang);
367                                 break;
368                         case 'H':
369                         case 'k':
370                                 /* 24-Hour */
371                                 if (format[offset] == 'H') {
372                                         /* e.g. oh-eight */
373                                         if (tm.tm_hour < 10) {
374                                                 res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
375                                         }
376                                 } else {
377                                         /* e.g. eight */
378                                         if (tm.tm_hour == 0) {
379                                                 res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
380                                         }
381                                 }
382                                 if (!res) {
383                                         if (tm.tm_hour != 0) {
384                                                 int remainder = tm.tm_hour;
385                                                 if (tm.tm_hour > 20) {
386                                                         res = wait_file(chan,ints,AST_SOUNDS "/digits/20",lang);
387                                                         remainder -= 20;
388                                                 }
389                                                 if (!res) {
390                                                         snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/digits/%d", remainder);
391                                                         res = wait_file(chan,ints,nextmsg,lang);
392                                                 }
393                                         }
394                                 }
395                                 break;
396                         case 'M':
397                                 /* Minute */
398                                 if (tm.tm_min == 0) {
399                                         res = wait_file(chan,ints,DIGITS_DIR "oclock",lang);
400                                 } else if (tm.tm_min < 10) {
401                                         res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
402                                         if (!res) {
403                                                 snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min);
404                                                 res = wait_file(chan,ints,nextmsg,lang);
405                                         }
406                                 } else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
407                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min);
408                                         res = wait_file(chan,ints,nextmsg,lang);
409                                 } else {
410                                         int ten, one;
411                                         ten = (tm.tm_min / 10) * 10;
412                                         one = (tm.tm_min % 10);
413                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten);
414                                         res = wait_file(chan,ints,nextmsg,lang);
415                                         if (!res) {
416                                                 /* Fifty, not fifty-zero */
417                                                 if (one != 0) {
418                                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one);
419                                                         res = wait_file(chan,ints,nextmsg,lang);
420                                                 }
421                                         }
422                                 }
423                                 break;
424                         case 'P':
425                         case 'p':
426                                 /* AM/PM */
427                                 if (tm.tm_hour > 11)
428                                         snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "p-m");
429                                 else
430                                         snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "a-m");
431                                 res = wait_file(chan,ints,nextmsg,lang);
432                                 break;
433                         case 'Q':
434                                 /* Shorthand for "Today", "Yesterday", or ABdY */
435                                 {
436                                         struct timeval now;
437                                         struct tm tmnow;
438                                         time_t beg_today;
439
440                                         gettimeofday(&now,NULL);
441                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
442                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
443                                         /* In any case, it saves not having to do ast_mktime() */
444                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
445                                         if (beg_today < time) {
446                                                 /* Today */
447                                                 res = wait_file(chan,ints,DIGITS_DIR "today",lang);
448                                         } else if (beg_today - 86400 < time) {
449                                                 /* Yesterday */
450                                                 res = wait_file(chan,ints,DIGITS_DIR "yesterday",lang);
451                                         } else {
452                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
453                                         }
454                                 }
455                                 break;
456                         case 'q':
457                                 /* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
458                                 {
459                                         struct timeval now;
460                                         struct tm tmnow;
461                                         time_t beg_today;
462
463                                         gettimeofday(&now,NULL);
464                                         ast_localtime(&now.tv_sec,&tmnow,timezone);
465                                         /* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
466                                         /* In any case, it saves not having to do ast_mktime() */
467                                         beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
468                                         if (beg_today < time) {
469                                                 /* Today */
470                                         } else if ((beg_today - 86400) < time) {
471                                                 /* Yesterday */
472                                                 res = wait_file(chan,ints,DIGITS_DIR "yesterday",lang);
473                                         } else if (beg_today - 86400 * 6 < time) {
474                                                 /* Within the last week */
475                                                 res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
476                                         } else {
477                                                 res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
478                                         }
479                                 }
480                                 break;
481                         case 'R':
482                                 res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
483                                 break;
484                         case 'S':
485                                 /* Seconds */
486                                 if (tm.tm_sec == 0) {
487                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_sec);
488                                         res = wait_file(chan,ints,nextmsg,lang);
489                                 } else if (tm.tm_sec < 10) {
490                                         res = wait_file(chan,ints,DIGITS_DIR "oh",lang);
491                                         if (!res) {
492                                                 snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_sec);
493                                                 res = wait_file(chan,ints,nextmsg,lang);
494                                         }
495                                 } else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
496                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_sec);
497                                         res = wait_file(chan,ints,nextmsg,lang);
498                                 } else {
499                                         int ten, one;
500                                         ten = (tm.tm_sec / 10) * 10;
501                                         one = (tm.tm_sec % 10);
502                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten);
503                                         res = wait_file(chan,ints,nextmsg,lang);
504                                         if (!res) {
505                                                 /* Fifty, not fifty-zero */
506                                                 if (one != 0) {
507                                                         snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one);
508                                                         res = wait_file(chan,ints,nextmsg,lang);
509                                                 }
510                                         }
511                                 }
512                                 break;
513                         case 'T':
514                                 res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
515                                 break;
516                         case ' ':
517                         case '  ':
518                                 /* Just ignore spaces and tabs */
519                                 break;
520                         default:
521                                 /* Unknown character */
522                                 ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
523                 }
524                 /* Jump out on DTMF */
525                 if (res) {
526                         break;
527                 }
528         }
529         return res;
530 }
531
532 int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang)
533 {
534         struct tm tm;
535         int res = 0;
536         int hour, pm=0;
537         localtime_r(&t,&tm);
538         hour = tm.tm_hour;
539         if (!hour)
540                 hour = 12;
541         else if (hour == 12)
542                 pm = 1;
543         else if (hour > 12) {
544                 hour -= 12;
545                 pm = 1;
546         }
547         if (!res)
548                 res = ast_say_number(chan, hour, ints, lang);
549
550         if (tm.tm_min > 9) {
551                 if (!res)
552                         res = ast_say_number(chan, tm.tm_min, ints, lang);
553         } else if (tm.tm_min) {
554                 if (!res)
555                         res = ast_streamfile(chan, "digits/oh", lang);
556                 if (!res)
557                         res = ast_waitstream(chan, ints);
558                 if (!res)
559                         res = ast_say_number(chan, tm.tm_min, ints, lang);
560         } else {
561                 if (!res)
562                         res = ast_streamfile(chan, "digits/oclock", lang);
563                 if (!res)
564                         res = ast_waitstream(chan, ints);
565         }
566         if (pm) {
567                 if (!res)
568                         res = ast_streamfile(chan, "digits/p-m", lang);
569         } else {
570                 if (!res)
571                         res = ast_streamfile(chan, "digits/a-m", lang);
572         }
573         if (!res)
574                 res = ast_waitstream(chan, ints);
575         return res;
576 }
577
578 int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang)
579 {
580         struct tm tm;
581         char fn[256];
582         int res = 0;
583         int hour, pm=0;
584         localtime_r(&t,&tm);
585         if (!res) {
586                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
587                 res = ast_streamfile(chan, fn, lang);
588                 if (!res)
589                         res = ast_waitstream(chan, ints);
590         }
591         if (!res) {
592                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
593                 res = ast_streamfile(chan, fn, lang);
594                 if (!res)
595                         res = ast_waitstream(chan, ints);
596         }
597         if (!res)
598                 res = ast_say_number(chan, tm.tm_mday, ints, lang);
599
600         hour = tm.tm_hour;
601         if (!hour)
602                 hour = 12;
603         else if (hour == 12)
604                 pm = 1;
605         else if (hour > 12) {
606                 hour -= 12;
607                 pm = 1;
608         }
609         if (!res)
610                 res = ast_say_number(chan, hour, ints, lang);
611
612         if (tm.tm_min > 9) {
613                 if (!res)
614                         res = ast_say_number(chan, tm.tm_min, ints, lang);
615         } else if (tm.tm_min) {
616                 if (!res)
617                         res = ast_streamfile(chan, "digits/oh", lang);
618                 if (!res)
619                         res = ast_waitstream(chan, ints);
620                 if (!res)
621                         res = ast_say_number(chan, tm.tm_min, ints, lang);
622         } else {
623                 if (!res)
624                         res = ast_streamfile(chan, "digits/oclock", lang);
625                 if (!res)
626                         res = ast_waitstream(chan, ints);
627         }
628         if (pm) {
629                 if (!res)
630                         res = ast_streamfile(chan, "digits/p-m", lang);
631         } else {
632                 if (!res)
633                         res = ast_streamfile(chan, "digits/a-m", lang);
634         }
635         if (!res)
636                 res = ast_waitstream(chan, ints);
637         if (!res)
638                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang);
639         return res;
640 }
641
642 int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang)
643 {
644         int res=0;
645         time_t nowt;
646         int daydiff;
647         struct tm tm;
648         struct tm now;
649         char fn[256];
650
651         time(&nowt);
652
653         localtime_r(&t,&tm);
654         localtime_r(&nowt,&now);
655         daydiff = now.tm_yday - tm.tm_yday;
656         if ((daydiff < 0) || (daydiff > 6)) {
657                 /* Day of month and month */
658                 if (!res) {
659                         snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
660                         res = ast_streamfile(chan, fn, lang);
661                         if (!res)
662                                 res = ast_waitstream(chan, ints);
663                 }
664                 if (!res)
665                         res = ast_say_number(chan, tm.tm_mday, ints, lang);
666
667         } else if (daydiff) {
668                 /* Just what day of the week */
669                 if (!res) {
670                         snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
671                         res = ast_streamfile(chan, fn, lang);
672                         if (!res)
673                                 res = ast_waitstream(chan, ints);
674                 }
675         } /* Otherwise, it was today */
676         if (!res)
677                 res = ast_say_time(chan, t, ints, lang);
678         return res;
679 }
680