Make ADPCM frames standard
[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.h"
31 #include "astconf.h"
32
33 /* set timeout to 0 for "standard" timeouts. Set timeout to -1 for 
34    "ludicrous time" (essentially never times out) */
35 int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout)
36 {
37         int res,to,fto;
38         /* XXX Merge with full version? XXX */
39         if (prompt) {
40                 res = ast_streamfile(c, prompt, c->language);
41                 if (res < 0)
42                         return res;
43         }
44         fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000;
45         to = c->pbx ? c->pbx->dtimeout * 1000 : 2000;
46
47         if (timeout > 0) fto = to = timeout;
48         if (timeout < 0) fto = to = 1000000000;
49         res = ast_readstring(c, s, maxlen, to, fto, "#");
50         return res;
51 }
52
53
54 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd)
55 {
56         int res,to,fto;
57         if (prompt) {
58                 res = ast_streamfile(c, prompt, c->language);
59                 if (res < 0)
60                         return res;
61         }
62         fto = 6000;
63         to = 2000;
64         if (timeout > 0) fto = to = timeout;
65         if (timeout < 0) fto = to = 1000000000;
66         res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd);
67         return res;
68 }
69
70 int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec)
71 {
72         int res;
73         struct ast_filestream *writer;
74         int rfmt;
75         int totalms=0, total;
76         
77         struct ast_frame *f;
78         struct ast_dsp *sildet;
79         /* Play prompt if requested */
80         if (prompt) {
81                 res = ast_streamfile(c, prompt, c->language);
82                 if (res < 0)
83                         return res;
84                 res = ast_waitstream(c,"");
85                 if (res < 0)
86                         return res;
87         }
88         rfmt = c->readformat;
89         res = ast_set_read_format(c, AST_FORMAT_SLINEAR);
90         if (res < 0) {
91                 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
92                 return -1;
93         }
94         sildet = ast_dsp_new();
95         if (!sildet) {
96                 ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
97                 return -1;
98         }
99         writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666);
100         if (!writer) {
101                 ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt);
102                 ast_dsp_free(sildet);
103                 return -1;
104         }
105         for(;;) {
106                 if ((res = ast_waitfor(c, 2000)) < 0) {
107                         ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt);
108                         break;
109                 }
110                 if (res) {
111                         f = ast_read(c);
112                         if (!f) {
113                                 ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt);
114                                 break;
115                         }
116                         if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) {
117                                 /* Ended happily with DTMF */
118                                 ast_frfree(f);
119                                 break;
120                         } else if (f->frametype == AST_FRAME_VOICE) {
121                                 ast_dsp_silence(sildet, f, &total); 
122                                 if (total > silence) {
123                                         /* Ended happily with silence */
124                                         ast_frfree(f);
125                                         break;
126                                 }
127                                 totalms += f->samples / 8;
128                                 if (totalms > maxsec * 1000) {
129                                         /* Ended happily with too much stuff */
130                                         ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec);
131                                         ast_frfree(f);
132                                         break;
133                                 }
134                         }
135                         ast_frfree(f);
136                 }
137         }
138         res = ast_set_read_format(c, rfmt);
139         if (res)
140                 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name);
141         ast_dsp_free(sildet);
142         ast_closestream(writer);
143         return 0;
144 }
145
146 int ast_app_has_voicemail(const char *mailbox)
147 {
148         DIR *dir;
149         struct dirent *de;
150         char fn[256];
151         char tmp[256]="";
152         char *mb, *cur;
153         char *context;
154         int ret;
155         /* If no mailbox, return immediately */
156         if (!strlen(mailbox))
157                 return 0;
158         if (strchr(mailbox, ',')) {
159                 strncpy(tmp, mailbox, sizeof(tmp));
160                 mb = tmp;
161                 ret = 0;
162                 while((cur = strsep(&mb, ","))) {
163                         if (strlen(cur)) {
164                                 if (ast_app_has_voicemail(cur))
165                                         return 1; 
166                         }
167                 }
168                 return 0;
169         }
170         strncpy(tmp, mailbox, sizeof(tmp) - 1);
171         context = strchr(tmp, '@');
172         if (context) {
173                 *context = '\0';
174                 context++;
175         } else
176                 context = "default";
177         snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
178         dir = opendir(fn);
179         if (!dir)
180                 return 0;
181         while ((de = readdir(dir))) {
182                 if (!strncasecmp(de->d_name, "msg", 3))
183                         break;
184         }
185         closedir(dir);
186         if (de)
187                 return 1;
188         return 0;
189 }
190
191 int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
192 {
193         DIR *dir;
194         struct dirent *de;
195         char fn[256];
196         char tmp[256]="";
197         char *mb, *cur;
198         char *context;
199         int ret;
200         if (newmsgs)
201                 *newmsgs = 0;
202         if (oldmsgs)
203                 *oldmsgs = 0;
204         /* If no mailbox, return immediately */
205         if (!strlen(mailbox))
206                 return 0;
207         if (strchr(mailbox, ',')) {
208                 int tmpnew, tmpold;
209                 strncpy(tmp, mailbox, sizeof(tmp));
210                 mb = tmp;
211                 ret = 0;
212                 while((cur = strsep(&mb, ", "))) {
213                         if (strlen(cur)) {
214                                 if (ast_app_messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
215                                         return -1;
216                                 else {
217                                         if (newmsgs)
218                                                 *newmsgs += tmpnew; 
219                                         if (oldmsgs)
220                                                 *oldmsgs += tmpold;
221                                 }
222                         }
223                 }
224                 return 0;
225         }
226         strncpy(tmp, mailbox, sizeof(tmp) - 1);
227         context = strchr(tmp, '@');
228         if (context) {
229                 *context = '\0';
230                 context++;
231         } else
232                 context = "default";
233         if (newmsgs) {
234                 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
235                 dir = opendir(fn);
236                 if (dir) {
237                         while ((de = readdir(dir))) {
238                                 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
239                                         !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
240                                                 (*newmsgs)++;
241                                         
242                         }
243                         closedir(dir);
244                 }
245         }
246         if (oldmsgs) {
247                 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/Old", (char *)ast_config_AST_SPOOL_DIR, context, tmp);
248                 dir = opendir(fn);
249                 if (dir) {
250                         while ((de = readdir(dir))) {
251                                 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
252                                         !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
253                                                 (*oldmsgs)++;
254                                         
255                         }
256                         closedir(dir);
257                 }
258         }
259         return 0;
260 }