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