Add pound/star (bug #113)
[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 <asterisk/file.h>
16 #include <asterisk/channel.h>
17 #include <asterisk/logger.h>
18 #include <asterisk/say.h>
19 #include <stdio.h>
20
21 int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
22 {
23         /* XXX Merge with full version? XXX */
24         char fn[256] = "";
25         int num = 0;
26         int res = 0;
27         while(fn2[num] && !res) {
28                 switch (fn2[num]) {
29                         case ('*'):
30                                 snprintf(fn, sizeof(fn), "digits/star");
31                                 break;
32                         case ('#'):
33                                 snprintf(fn, sizeof(fn), "digits/pound");
34                                 break;
35                         default:
36                                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
37                         }
38                 res = ast_streamfile(chan, fn, lang);
39                 if (!res) 
40                         res = ast_waitstream(chan, ints);
41                 ast_stopstream(chan);
42                 num++;
43         }
44         return res;
45 }
46
47 int ast_say_digit_str_full(struct ast_channel *chan, char *fn2, char *ints, char *lang, int audiofd, int ctrlfd)
48 {
49         char fn[256] = "";
50         int num = 0;
51         int res = 0;
52         while(fn2[num] && !res) {
53                 snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
54                 res = ast_streamfile(chan, fn, lang);
55                 if (!res) 
56                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
57                 ast_stopstream(chan);
58                 num++;
59         }
60         return res;
61 }
62
63 int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang)
64 {
65         /* XXX Should I be merged with say_digits_full XXX */
66         char fn2[256];
67         snprintf(fn2, sizeof(fn2), "%d", num);
68         return ast_say_digit_str(chan, fn2, ints, lang);
69 }
70
71 int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lang, int audiofd, int ctrlfd)
72 {
73         char fn2[256];
74         snprintf(fn2, sizeof(fn2), "%d", num);
75         return ast_say_digit_str_full(chan, fn2, ints, lang, audiofd, ctrlfd);
76 }
77
78 int ast_say_number_full(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
79 {
80         int res = 0;
81         int playh = 0;
82         char fn[256] = "";
83         if (!num) 
84                 return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
85         if (0) {
86         /* XXX Only works for english XXX */
87         } else {
88                 /* Use english numbers */
89                 language = "en";
90                 while(!res && (num || playh)) {
91                         if (playh) {
92                                 snprintf(fn, sizeof(fn), "digits/hundred");
93                                 playh = 0;
94                         } else
95                         if (num < 20) {
96                                 snprintf(fn, sizeof(fn), "digits/%d", num);
97                                 num = 0;
98                         } else
99                         if (num < 100) {
100                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
101                                 num -= ((num / 10) * 10);
102                         } else {
103                                 if (num < 1000){
104                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
105                                         playh++;
106                                         num -= ((num / 100) * 100);
107                                 } else {
108                                         if (num < 1000000) {
109                                                 res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd);
110                                                 if (res)
111                                                         return res;
112                                                 num = num % 1000;
113                                                 snprintf(fn, sizeof(fn), "digits/thousand");
114                                         } else {
115                                                 if (num < 1000000000) {
116                                                         res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd);
117                                                         if (res)
118                                                                 return res;
119                                                         num = num % 1000000;
120                                                         snprintf(fn, sizeof(fn), "digits/million");
121                                                 } else {
122                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
123                                                         res = -1;
124                                                 }
125                                         }
126                                 }
127                         }
128                         if (!res) {
129                                 res = ast_streamfile(chan, fn, language);
130                                 if (!res) 
131                                         res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
132                                 ast_stopstream(chan);
133                         }
134                         
135                 }
136         }
137         return res;
138 }
139
140 int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language)
141 {
142         /* XXX Should I be merged with ast_say_number_full XXX */
143         int res = 0;
144         int playh = 0;
145         char fn[256] = "";
146         if (!num) 
147                 return ast_say_digits(chan, 0,ints, language);
148         if (0) {
149         /* XXX Only works for english XXX */
150         } else {
151                 /* Use english numbers */
152                 language = "en";
153                 while(!res && (num || playh)) {
154                         if (playh) {
155                                 snprintf(fn, sizeof(fn), "digits/hundred");
156                                 playh = 0;
157                         } else
158                         if (num < 20) {
159                                 snprintf(fn, sizeof(fn), "digits/%d", num);
160                                 num = 0;
161                         } else
162                         if (num < 100) {
163                                 snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
164                                 num -= ((num / 10) * 10);
165                         } else {
166                                 if (num < 1000){
167                                         snprintf(fn, sizeof(fn), "digits/%d", (num/100));
168                                         playh++;
169                                         num -= ((num / 100) * 100);
170                                 } else {
171                                         if (num < 1000000) {
172                                                 res = ast_say_number(chan, num / 1000, ints, language);
173                                                 if (res)
174                                                         return res;
175                                                 num = num % 1000;
176                                                 snprintf(fn, sizeof(fn), "digits/thousand");
177                                         } else {
178                                                 if (num < 1000000000) {
179                                                         res = ast_say_number(chan, num / 1000000, ints, language);
180                                                         if (res)
181                                                                 return res;
182                                                         num = num % 1000000;
183                                                         snprintf(fn, sizeof(fn), "digits/million");
184                                                 } else {
185                                                         ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
186                                                         res = -1;
187                                                 }
188                                         }
189                                 }
190                         }
191                         if (!res) {
192                                 res = ast_streamfile(chan, fn, language);
193                                 if (!res) 
194                                         res = ast_waitstream(chan, ints);
195                                 ast_stopstream(chan);
196                         }
197                         
198                 }
199         }
200         return res;
201 }
202 int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
203 {
204         struct tm tm;
205         char fn[256];
206         int res = 0;
207         localtime_r(&t,&tm);
208         if (!&tm) {
209                 ast_log(LOG_WARNING, "Unable to derive local time\n");
210                 return -1;
211         }
212         if (!res) {
213                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
214                 res = ast_streamfile(chan, fn, lang);
215                 if (!res)
216                         res = ast_waitstream(chan, ints);
217         }
218         if (!res) {
219                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
220                 res = ast_streamfile(chan, fn, lang);
221                 if (!res)
222                         res = ast_waitstream(chan, ints);
223         }
224         if (!res)
225                 res = ast_say_number(chan, tm.tm_mday, ints, lang);
226
227         if (!res)
228                 res = ast_waitstream(chan, ints);
229         if (!res)
230                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang);
231         return res;
232 }
233
234 int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang)
235 {
236         struct tm tm;
237         int res = 0;
238         int hour, pm=0;
239         localtime_r(&t,&tm);
240         if (!&tm) {
241                 ast_log(LOG_WARNING, "Unable to derive local time\n");
242                 return -1;
243         }
244         hour = tm.tm_hour;
245         if (!hour)
246                 hour = 12;
247         else if (hour == 12)
248                 pm = 1;
249         else if (hour > 12) {
250                 hour -= 12;
251                 pm = 1;
252         }
253         if (!res)
254                 res = ast_say_number(chan, hour, ints, lang);
255
256         if (tm.tm_min > 9) {
257                 if (!res)
258                         res = ast_say_number(chan, tm.tm_min, ints, lang);
259         } else if (tm.tm_min) {
260                 if (!res)
261                         res = ast_streamfile(chan, "digits/oh", lang);
262                 if (!res)
263                         res = ast_waitstream(chan, ints);
264                 if (!res)
265                         res = ast_say_number(chan, tm.tm_min, ints, lang);
266         } else {
267                 if (!res)
268                         res = ast_streamfile(chan, "digits/oclock", lang);
269                 if (!res)
270                         res = ast_waitstream(chan, ints);
271         }
272         if (pm) {
273                 if (!res)
274                         res = ast_streamfile(chan, "digits/p-m", lang);
275         } else {
276                 if (!res)
277                         res = ast_streamfile(chan, "digits/a-m", lang);
278         }
279         if (!res)
280                 res = ast_waitstream(chan, ints);
281         return res;
282 }
283
284 int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang)
285 {
286         struct tm tm;
287         char fn[256];
288         int res = 0;
289         int hour, pm=0;
290         localtime_r(&t,&tm);
291         if (!&tm) {
292                 ast_log(LOG_WARNING, "Unable to derive local time\n");
293                 return -1;
294         }
295         if (!res) {
296                 snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
297                 res = ast_streamfile(chan, fn, lang);
298                 if (!res)
299                         res = ast_waitstream(chan, ints);
300         }
301         if (!res) {
302                 snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
303                 res = ast_streamfile(chan, fn, lang);
304                 if (!res)
305                         res = ast_waitstream(chan, ints);
306         }
307         if (!res)
308                 res = ast_say_number(chan, tm.tm_mday, ints, lang);
309
310         hour = tm.tm_hour;
311         if (!hour)
312                 hour = 12;
313         else if (hour == 12)
314                 pm = 1;
315         else if (hour > 12) {
316                 hour -= 12;
317                 pm = 1;
318         }
319         if (!res)
320                 res = ast_say_number(chan, hour, ints, lang);
321
322         if (tm.tm_min > 9) {
323                 if (!res)
324                         res = ast_say_number(chan, tm.tm_min, ints, lang);
325         } else if (tm.tm_min) {
326                 if (!res)
327                         res = ast_streamfile(chan, "digits/oh", lang);
328                 if (!res)
329                         res = ast_waitstream(chan, ints);
330                 if (!res)
331                         res = ast_say_number(chan, tm.tm_min, ints, lang);
332         } else {
333                 if (!res)
334                         res = ast_streamfile(chan, "digits/oclock", lang);
335                 if (!res)
336                         res = ast_waitstream(chan, ints);
337         }
338         if (pm) {
339                 if (!res)
340                         res = ast_streamfile(chan, "digits/p-m", lang);
341         } else {
342                 if (!res)
343                         res = ast_streamfile(chan, "digits/a-m", lang);
344         }
345         if (!res)
346                 res = ast_waitstream(chan, ints);
347         if (!res)
348                 res = ast_say_number(chan, tm.tm_year + 1900, ints, lang);
349         return res;
350 }
351
352 int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang)
353 {
354         int res=0;
355         time_t nowt;
356         int daydiff;
357         struct tm tm;
358         struct tm now;
359         char fn[256];
360
361         time(&nowt);
362
363         localtime_r(&t,&tm);
364         if (!&tm) {
365                 ast_log(LOG_WARNING, "Unable to derive local time\n");
366                 return -1;
367         }
368         localtime_r(&nowt,&now);
369         daydiff = now.tm_yday - tm.tm_yday;
370         if ((daydiff < 0) || (daydiff > 6)) {
371                 /* Day of month and month */
372                 if (!res) {
373                         snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
374                         res = ast_streamfile(chan, fn, lang);
375                         if (!res)
376                                 res = ast_waitstream(chan, ints);
377                 }
378                 if (!res)
379                         res = ast_say_number(chan, tm.tm_mday, ints, lang);
380
381         } else if (daydiff) {
382                 /* Just what day of the week */
383                 if (!res) {
384                         snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
385                         res = ast_streamfile(chan, fn, lang);
386                         if (!res)
387                                 res = ast_waitstream(chan, ints);
388                 }
389         } /* Otherwise, it was today */
390         if (!res)
391                 res = ast_say_time(chan, t, ints, lang);
392         return res;
393 }
394