Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

app.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Channel Management 00005 * 00006 * Copyright (C) 1999, Mark Spencer 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License 00012 */ 00013 00014 #include <stdio.h> 00015 #include <stdlib.h> 00016 #include <pthread.h> 00017 #include <string.h> 00018 #include <sys/time.h> 00019 #include <signal.h> 00020 #include <errno.h> 00021 #include <unistd.h> 00022 #include <dirent.h> 00023 #include <asterisk/channel.h> 00024 #include <asterisk/pbx.h> 00025 #include <asterisk/file.h> 00026 #include <asterisk/app.h> 00027 #include <asterisk/dsp.h> 00028 #include <asterisk/logger.h> 00029 #include <asterisk/options.h> 00030 #include <asterisk/utils.h> 00031 #include "asterisk.h" 00032 #include "astconf.h" 00033 00034 /* set timeout to 0 for "standard" timeouts. Set timeout to -1 for 00035 "ludicrous time" (essentially never times out) */ 00036 int ast_app_getdata(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout) 00037 { 00038 int res,to,fto; 00039 /* XXX Merge with full version? XXX */ 00040 if (prompt) { 00041 res = ast_streamfile(c, prompt, c->language); 00042 if (res < 0) 00043 return res; 00044 } 00045 fto = c->pbx ? c->pbx->rtimeout * 1000 : 6000; 00046 to = c->pbx ? c->pbx->dtimeout * 1000 : 2000; 00047 00048 if (timeout > 0) fto = to = timeout; 00049 if (timeout < 0) fto = to = 1000000000; 00050 res = ast_readstring(c, s, maxlen, to, fto, "#"); 00051 return res; 00052 } 00053 00054 00055 int ast_app_getdata_full(struct ast_channel *c, char *prompt, char *s, int maxlen, int timeout, int audiofd, int ctrlfd) 00056 { 00057 int res,to,fto; 00058 if (prompt) { 00059 res = ast_streamfile(c, prompt, c->language); 00060 if (res < 0) 00061 return res; 00062 } 00063 fto = 6000; 00064 to = 2000; 00065 if (timeout > 0) fto = to = timeout; 00066 if (timeout < 0) fto = to = 1000000000; 00067 res = ast_readstring_full(c, s, maxlen, to, fto, "#", audiofd, ctrlfd); 00068 return res; 00069 } 00070 00071 int ast_app_getvoice(struct ast_channel *c, char *dest, char *dstfmt, char *prompt, int silence, int maxsec) 00072 { 00073 int res; 00074 struct ast_filestream *writer; 00075 int rfmt; 00076 int totalms=0, total; 00077 00078 struct ast_frame *f; 00079 struct ast_dsp *sildet; 00080 /* Play prompt if requested */ 00081 if (prompt) { 00082 res = ast_streamfile(c, prompt, c->language); 00083 if (res < 0) 00084 return res; 00085 res = ast_waitstream(c,""); 00086 if (res < 0) 00087 return res; 00088 } 00089 rfmt = c->readformat; 00090 res = ast_set_read_format(c, AST_FORMAT_SLINEAR); 00091 if (res < 0) { 00092 ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n"); 00093 return -1; 00094 } 00095 sildet = ast_dsp_new(); 00096 if (!sildet) { 00097 ast_log(LOG_WARNING, "Unable to create silence detector :(\n"); 00098 return -1; 00099 } 00100 writer = ast_writefile(dest, dstfmt, "Voice file", 0, 0, 0666); 00101 if (!writer) { 00102 ast_log(LOG_WARNING, "Unable to open file '%s' in format '%s' for writing\n", dest, dstfmt); 00103 ast_dsp_free(sildet); 00104 return -1; 00105 } 00106 for(;;) { 00107 if ((res = ast_waitfor(c, 2000)) < 0) { 00108 ast_log(LOG_NOTICE, "Waitfor failed while recording file '%s' format '%s'\n", dest, dstfmt); 00109 break; 00110 } 00111 if (res) { 00112 f = ast_read(c); 00113 if (!f) { 00114 ast_log(LOG_NOTICE, "Hungup while recording file '%s' format '%s'\n", dest, dstfmt); 00115 break; 00116 } 00117 if ((f->frametype == AST_FRAME_DTMF) && (f->subclass == '#')) { 00118 /* Ended happily with DTMF */ 00119 ast_frfree(f); 00120 break; 00121 } else if (f->frametype == AST_FRAME_VOICE) { 00122 ast_dsp_silence(sildet, f, &total); 00123 if (total > silence) { 00124 /* Ended happily with silence */ 00125 ast_frfree(f); 00126 break; 00127 } 00128 totalms += f->samples / 8; 00129 if (totalms > maxsec * 1000) { 00130 /* Ended happily with too much stuff */ 00131 ast_log(LOG_NOTICE, "Constraining voice on '%s' to %d seconds\n", c->name, maxsec); 00132 ast_frfree(f); 00133 break; 00134 } 00135 } 00136 ast_frfree(f); 00137 } 00138 } 00139 res = ast_set_read_format(c, rfmt); 00140 if (res) 00141 ast_log(LOG_WARNING, "Unable to restore read format on '%s'\n", c->name); 00142 ast_dsp_free(sildet); 00143 ast_closestream(writer); 00144 return 0; 00145 } 00146 00147 int ast_app_has_voicemail(const char *mailbox) 00148 { 00149 DIR *dir; 00150 struct dirent *de; 00151 char fn[256]; 00152 char tmp[256]=""; 00153 char *mb, *cur; 00154 char *context; 00155 int ret; 00156 /* If no mailbox, return immediately */ 00157 if (ast_strlen_zero(mailbox)) 00158 return 0; 00159 if (strchr(mailbox, ',')) { 00160 strncpy(tmp, mailbox, sizeof(tmp)); 00161 mb = tmp; 00162 ret = 0; 00163 while((cur = strsep(&mb, ","))) { 00164 if (!ast_strlen_zero(cur)) { 00165 if (ast_app_has_voicemail(cur)) 00166 return 1; 00167 } 00168 } 00169 return 0; 00170 } 00171 strncpy(tmp, mailbox, sizeof(tmp) - 1); 00172 context = strchr(tmp, '@'); 00173 if (context) { 00174 *context = '\0'; 00175 context++; 00176 } else 00177 context = "default"; 00178 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp); 00179 dir = opendir(fn); 00180 if (!dir) 00181 return 0; 00182 while ((de = readdir(dir))) { 00183 if (!strncasecmp(de->d_name, "msg", 3)) 00184 break; 00185 } 00186 closedir(dir); 00187 if (de) 00188 return 1; 00189 return 0; 00190 } 00191 00192 int ast_app_messagecount(const char *mailbox, int *newmsgs, int *oldmsgs) 00193 { 00194 DIR *dir; 00195 struct dirent *de; 00196 char fn[256]; 00197 char tmp[256]=""; 00198 char *mb, *cur; 00199 char *context; 00200 int ret; 00201 if (newmsgs) 00202 *newmsgs = 0; 00203 if (oldmsgs) 00204 *oldmsgs = 0; 00205 /* If no mailbox, return immediately */ 00206 if (ast_strlen_zero(mailbox)) 00207 return 0; 00208 if (strchr(mailbox, ',')) { 00209 int tmpnew, tmpold; 00210 strncpy(tmp, mailbox, sizeof(tmp)); 00211 mb = tmp; 00212 ret = 0; 00213 while((cur = strsep(&mb, ", "))) { 00214 if (!ast_strlen_zero(cur)) { 00215 if (ast_app_messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL)) 00216 return -1; 00217 else { 00218 if (newmsgs) 00219 *newmsgs += tmpnew; 00220 if (oldmsgs) 00221 *oldmsgs += tmpold; 00222 } 00223 } 00224 } 00225 return 0; 00226 } 00227 strncpy(tmp, mailbox, sizeof(tmp) - 1); 00228 context = strchr(tmp, '@'); 00229 if (context) { 00230 *context = '\0'; 00231 context++; 00232 } else 00233 context = "default"; 00234 if (newmsgs) { 00235 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/INBOX", (char *)ast_config_AST_SPOOL_DIR, context, tmp); 00236 dir = opendir(fn); 00237 if (dir) { 00238 while ((de = readdir(dir))) { 00239 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) && 00240 !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt")) 00241 (*newmsgs)++; 00242 00243 } 00244 closedir(dir); 00245 } 00246 } 00247 if (oldmsgs) { 00248 snprintf(fn, sizeof(fn), "%s/voicemail/%s/%s/Old", (char *)ast_config_AST_SPOOL_DIR, context, tmp); 00249 dir = opendir(fn); 00250 if (dir) { 00251 while ((de = readdir(dir))) { 00252 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) && 00253 !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt")) 00254 (*oldmsgs)++; 00255 00256 } 00257 closedir(dir); 00258 } 00259 } 00260 return 0; 00261 } 00262 00263 int ast_dtmf_stream(struct ast_channel *chan,struct ast_channel *peer,char *digits,int between) 00264 { 00265 char *ptr=NULL; 00266 int res=0; 00267 struct ast_frame f; 00268 if (!between) 00269 between = 100; 00270 00271 if (peer) 00272 res = ast_autoservice_start(peer); 00273 00274 if (!res) { 00275 res = ast_waitfor(chan,100); 00276 if (res > -1) { 00277 for (ptr=digits;*ptr;*ptr++) { 00278 if (*ptr == 'w') { 00279 res = ast_safe_sleep(chan, 500); 00280 if (res) 00281 break; 00282 continue; 00283 } 00284 memset(&f, 0, sizeof(f)); 00285 f.frametype = AST_FRAME_DTMF; 00286 f.subclass = *ptr; 00287 f.src = "ast_dtmf_stream"; 00288 if (strchr("0123456789*#abcdABCD",*ptr)==NULL) { 00289 ast_log(LOG_WARNING, "Illegal DTMF character '%c' in string. (0-9*#aAbBcCdD allowed)\n",*ptr); 00290 } else { 00291 res = ast_write(chan, &f); 00292 if (res) 00293 break; 00294 /* pause between digits */ 00295 res = ast_safe_sleep(chan,between); 00296 if (res) 00297 break; 00298 } 00299 } 00300 } 00301 if (peer) 00302 res = ast_autoservice_stop(peer); 00303 } 00304 return res; 00305 } 00306 00307 struct linear_state { 00308 int fd; 00309 int autoclose; 00310 int allowoverride; 00311 int origwfmt; 00312 }; 00313 00314 static void linear_release(struct ast_channel *chan, void *params) 00315 { 00316 struct linear_state *ls = params; 00317 if (ls->origwfmt && ast_set_write_format(chan, ls->origwfmt)) { 00318 ast_log(LOG_WARNING, "Unable to restore channel '%s' to format '%d'\n", chan->name, ls->origwfmt); 00319 } 00320 if (ls->autoclose) 00321 close(ls->fd); 00322 free(params); 00323 } 00324 00325 static int linear_generator(struct ast_channel *chan, void *data, int len, int samples) 00326 { 00327 struct ast_frame f; 00328 short buf[2048 + AST_FRIENDLY_OFFSET / 2]; 00329 struct linear_state *ls = data; 00330 int res; 00331 len = samples * 2; 00332 if (len > sizeof(buf) - AST_FRIENDLY_OFFSET) { 00333 ast_log(LOG_WARNING, "Can't generate %d bytes of data!\n" ,len); 00334 len = sizeof(buf) - AST_FRIENDLY_OFFSET; 00335 } 00336 memset(&f, 0, sizeof(f)); 00337 res = read(ls->fd, buf + AST_FRIENDLY_OFFSET/2, len); 00338 if (res > 0) { 00339 f.frametype = AST_FRAME_VOICE; 00340 f.subclass = AST_FORMAT_SLINEAR; 00341 f.data = buf + AST_FRIENDLY_OFFSET/2; 00342 f.datalen = res; 00343 f.samples = res / 2; 00344 f.offset = AST_FRIENDLY_OFFSET; 00345 ast_write(chan, &f); 00346 if (res == len) 00347 return 0; 00348 } 00349 return -1; 00350 } 00351 00352 static void *linear_alloc(struct ast_channel *chan, void *params) 00353 { 00354 struct linear_state *ls; 00355 /* In this case, params is already malloc'd */ 00356 if (params) { 00357 ls = params; 00358 if (ls->allowoverride) 00359 chan->writeinterrupt = 1; 00360 else 00361 chan->writeinterrupt = 0; 00362 ls->origwfmt = chan->writeformat; 00363 if (ast_set_write_format(chan, AST_FORMAT_SLINEAR)) { 00364 ast_log(LOG_WARNING, "Unable to set '%s' to linear format (write)\n", chan->name); 00365 free(ls); 00366 ls = params = NULL; 00367 } 00368 } 00369 return params; 00370 } 00371 00372 static struct ast_generator linearstream = 00373 { 00374 alloc: linear_alloc, 00375 release: linear_release, 00376 generate: linear_generator, 00377 }; 00378 00379 int ast_linear_stream(struct ast_channel *chan, const char *filename, int fd, int allowoverride) 00380 { 00381 struct linear_state *lin; 00382 char tmpf[256] = ""; 00383 int res = -1; 00384 int autoclose = 0; 00385 if (fd < 0) { 00386 if (!filename || ast_strlen_zero(filename)) 00387 return -1; 00388 autoclose = 1; 00389 if (filename[0] == '/') 00390 strncpy(tmpf, filename, sizeof(tmpf) - 1); 00391 else 00392 snprintf(tmpf, sizeof(tmpf), "%s/%s/%s", (char *)ast_config_AST_VAR_DIR, "sounds", filename); 00393 fd = open(tmpf, O_RDONLY); 00394 if (fd < 0){ 00395 ast_log(LOG_WARNING, "Unable to open file '%s': %s\n", tmpf, strerror(errno)); 00396 return -1; 00397 } 00398 } 00399 lin = malloc(sizeof(struct linear_state)); 00400 if (lin) { 00401 memset(lin, 0, sizeof(lin)); 00402 lin->fd = fd; 00403 lin->allowoverride = allowoverride; 00404 lin->autoclose = autoclose; 00405 res = ast_activate_generator(chan, &linearstream, lin); 00406 } 00407 return res; 00408 } 00409 00410 int ast_control_streamfile(struct ast_channel *chan, char *file, char *fwd, char *rev, char *stop, char *pause, int skipms) 00411 { 00412 struct timeval started, ended; 00413 long elapsed = 0,last_elapsed =0; 00414 char *breaks; 00415 int blen=2; 00416 int res=0; 00417 00418 if (stop) 00419 blen += strlen(stop); 00420 if (pause) 00421 blen += strlen(pause); 00422 00423 breaks = alloca(blen + 1); 00424 breaks[0] = '\0'; 00425 strcat(breaks, stop); 00426 strcat(breaks, pause); 00427 00428 if (chan->_state != AST_STATE_UP) 00429 res = ast_answer(chan); 00430 00431 if (chan) 00432 ast_stopstream(chan); 00433 00434 for (;;) { 00435 gettimeofday(&started,NULL); 00436 00437 if (chan) 00438 ast_stopstream(chan); 00439 res = ast_streamfile(chan, file, chan->language); 00440 if (!res) { 00441 res = 1; 00442 if (elapsed) { 00443 ast_stream_fastforward(chan->stream, elapsed); 00444 last_elapsed = elapsed - 200; 00445 } 00446 if (res) 00447 res = ast_waitstream_fr(chan, breaks, fwd, rev, skipms); 00448 else 00449 break; 00450 } 00451 00452 if (res < 1) 00453 break; 00454 00455 if (pause != NULL && strchr(pause, res)) { 00456 gettimeofday(&ended, NULL); 00457 elapsed = (((ended.tv_sec * 1000) + ended.tv_usec / 1000) - ((started.tv_sec * 1000) + started.tv_usec / 1000) + last_elapsed); 00458 for(;;) { 00459 if (chan) 00460 ast_stopstream(chan); 00461 res = ast_waitfordigit(chan, 1000); 00462 if(res == 0) 00463 continue; 00464 else if(res == -1 || strchr(pause, res) || (stop && strchr(stop, res))) 00465 break; 00466 } 00467 if (res == *pause) { 00468 res = 0; 00469 continue; 00470 } 00471 } 00472 if (res == -1) 00473 break; 00474 00475 if (stop && strchr(stop, res)) { 00476 res = 0; 00477 break; 00478 } 00479 } 00480 if (chan) 00481 ast_stopstream(chan); 00482 00483 return res; 00484 }

Generated on Sat Jun 12 16:40:57 2004 for Asterisk by doxygen 1.3.7