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