Created API call ast_dtmf_stream
[asterisk/asterisk.git] / app.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Channel Management
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 <stdio.h>
15 #include <stdlib.h>
16 #include <pthread.h>
17 #include <string.h>
18 #include <sys/time.h>
19 #include <signal.h>
20 #include <errno.h>
21 #include <unistd.h>
22 #include <dirent.h>
23 #include <asterisk/channel.h>
24 #include <asterisk/pbx.h>
25 #include <asterisk/file.h>
26 #include <asterisk/app.h>
27 #include <asterisk/dsp.h>
28 #include <asterisk/logger.h>
29 #include <asterisk/options.h>
30 #include <asterisk/utils.h>
31 #include "asterisk.h"
32 #include "astconf.h"
33
34 /* set timeout to 0 for "standard" timeouts. Set timeout to -1 for 
35    "ludicrous time" (essentially never times out) */
36 int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
37 {
38         int res,to,fto;
39         /* XXX Merge with full version? XXX */
40         if (prompt) {
41                 res = ast_streamfile(c, prompt, c->language);
42                 if (res < 0)
43                         return res;
44         }
45         fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
46         to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
47
48         if (timeout > 0) fto = to = timeout;
49         if (timeout < 0) fto = to = 1000000000;
50         res = ast_readstring(c, s, maxlen, to, fto, "#");
51         return res;
52 }
53
54
55 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
56 {
57         int res,to,fto;
58         if (prompt) {
59                 res = ast_streamfile(c, prompt, c->language);
60                 if (res < 0)
61                         return res;
62         }
63         fto = 6000;
64         to = 2000;
65         if (timeout > 0) fto = to = timeout;
66         if (timeout < 0) fto = to = 1000000000;
67         res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
68         return res;
69 }
70
71 int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
72 {
73         int res;
74         struct ast_filestream *writer;
75         int rfmt;
76         int totalms=0, total;
77         
78         struct ast_frame *f;
79         struct ast_dsp *sildet;
80         /* Play prompt if requested */
81         if (prompt) {
82                 res = ast_streamfile(c, prompt, c->language);
83                 if (res < 0)
84                         return res;
85                 res = ast_waitstream(c,"");
86                 if (res < 0)
87                         return res;
88         }
89         rfmt = c->readformat;
90         res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
91         if (res < 0) {
92                 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
93                 return -1;
94         }
95         sildet = ast_dsp_new();
96         if (!sildet) {
97                 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
98                 return -1;
99         }
100         writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
101         if (!writer) {
102                 ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
103                 ast_dsp_free(sildet);
104                 return -1;
105         }
106         for(;;) {
107                 if ((res = ast_waitfor(c, 2000)) < 0) {
108                         ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
109                         break;
110                 }
111                 if (res) {
112                         f = ast_read(c);
113                         if (!f) {
114                                 ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
115                                 break;
116                         }
117                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
118                                 /* Ended happily with DTMF */
119                                 ast_frfree(f);
120                                 break;
121                         } else if (f->frametype == AST_FRAME_VOICE) {
122                                 ast_dsp_silence(sildet, f, &total); 
123                                 if (total > silence) {
124                                         /* Ended happily with silence */
125                                         ast_frfree(f);
126                                         break;
127                                 }
128                                 totalms += f->samples / 8;
129                                 if (totalms > maxsec * 1000) {
130                                         /* Ended happily with too much stuff */
131                                         ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
132                                         ast_frfree(f);
133                                         break;
134                                 }
135                         }
136                         ast_frfree(f);
137                 }
138         }
139         res = ast_set_read_format(c, rfmt);
140         if (res)
141                 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
142         ast_dsp_free(sildet);
143         ast_closestream(writer);
144         return 0;
145 }
146
147 int ast_app_has_voicemail(const char *mailbox)
148 {
149         DIR *dir;
150         struct dirent *de;
151         char fn[256];
152         char tmp[256]="";
153         char *mb, *cur;
154         char *context;
155         int ret;
156         /* If no mailbox, return immediately */
157         if (ast_strlen_zero(mailbox))
158                 return 0;
159         if (strchr(mailbox, ',')) {
160                 strncpy(tmp, mailbox, sizeof(tmp));
161                 mb = tmp;
162                 ret = 0;
163                 while((cur = strsep(&mb, ","))) {
164                         if (!ast_strlen_zero(cur)) {
165                                 if (ast_app_has_voicemail(cur))
166                                         return 1; 
167                         }
168                 }
169                 return 0;
170         }
171         strncpy(tmp, mailbox, sizeof(tmp) - 1);
172         context = strchr(tmp, '@');
173         if (context) {
174                 *context = '\0';
175                 context++;
176         } else
177                 context = "default";
178         snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
179         dir = opendir(fn);
180         if (!dir)
181                 return 0;
182         while ((de = readdir(dir))) {
183                 if (!strncasecmp(de->d_name, "msg", 3))
184                         break;
185         }
186         closedir(dir);
187         if (de)
188                 return 1;
189         return 0;
190 }
191
192 int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
193 {
194         DIR *dir;
195         struct dirent *de;
196         char fn[256];
197         char tmp[256]="";
198         char *mb, *cur;
199         char *context;
200         int ret;
201         if (newmsgs)
202                 *newmsgs = 0;
203         if (oldmsgs)
204                 *oldmsgs = 0;
205         /* If no mailbox, return immediately */
206         if (ast_strlen_zero(mailbox))
207                 return 0;
208         if (strchr(mailbox, ',')) {
209                 int tmpnew, tmpold;
210                 strncpy(tmp, mailbox, sizeof(tmp));
211                 mb = tmp;
212                 ret = 0;
213                 while((cur = strsep(&mb, ", "))) {
214                         if (!ast_strlen_zero(cur)) {
215                                 if (ast_app_messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
216                                         return -1;
217                                 else {
218                                         if (newmsgs)
219                                                 *newmsgs += tmpnew; 
220                                         if (oldmsgs)
221                                                 *oldmsgs += tmpold;
222                                 }
223                         }
224                 }
225                 return 0;
226         }
227         strncpy(tmp, mailbox, sizeof(tmp) - 1);
228         context = strchr(tmp, '@');
229         if (context) {
230                 *context = '\0';
231                 context++;
232         } else
233                 context = "default";
234         if (newmsgs) {
235                 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
236                 dir = opendir(fn);
237                 if (dir) {
238                         while ((de = readdir(dir))) {
239                                 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
240                                         !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
241                                                 (*newmsgs)++;
242                                         
243                         }
244                         closedir(dir);
245                 }
246         }
247         if (oldmsgs) {
248                 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/Old", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
249                 dir = opendir(fn);
250                 if (dir) {
251                         while ((de = readdir(dir))) {
252                                 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
253                                         !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
254                                                 (*oldmsgs)++;
255                                         
256                         }
257                         closedir(dir);
258                 }
259         }
260         return 0;
261 }
262
263 int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between) {
264   char *ptr=NULL;
265   int res=0;
266   struct ast_frame f;
267   if(!between)
268     between = 100;
269   
270   if(peer)
271     res = ast_autoservice_start(peer);
272
273   if (!res) {
274     res = ast_waitfor(chan,100);
275     if(res > -1) {
276       for(ptr=digits;*ptr;*ptr++) {
277         if(*ptr == 'w') {
278           res = ast_safe_sleep(chan, 500);
279           if(res) 
280             break;
281           continue;
282         }
283         memset(&f, 0, sizeof(f));
284         f.frametype = AST_FRAME_DTMF;
285         f.subclass = *ptr;
286         f.src = "ast_dtmf_stream";
287         if (strchr("0123456789*#abcdABCD",*ptr)==NULL) {
288           ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr);
289         } 
290         else {
291           res = ast_write(chan, &f);
292           if (res) 
293             break;
294           /* pause between digits */
295           res = ast_safe_sleep(chan,between);
296           if (res) 
297             break;
298         }
299       }
300     }
301     if(peer)
302       res = ast_autoservice_stop(peer);
303   }
304
305   return res;
306 }