00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include "asterisk.h"
00027
00028 ASTERISK_FILE_VERSION(__FILE__, "$Revision: 71068 $")
00029
00030 #include <sys/types.h>
00031 #include <errno.h>
00032 #include <unistd.h>
00033 #include <stdlib.h>
00034 #include <string.h>
00035 #include <stdio.h>
00036 #include <fcntl.h>
00037 #include <dirent.h>
00038 #include <sys/types.h>
00039 #include <sys/stat.h>
00040
00041 #include "asterisk/frame.h"
00042 #include "asterisk/file.h"
00043 #include "asterisk/cli.h"
00044 #include "asterisk/logger.h"
00045 #include "asterisk/channel.h"
00046 #include "asterisk/sched.h"
00047 #include "asterisk/options.h"
00048 #include "asterisk/translate.h"
00049 #include "asterisk/utils.h"
00050 #include "asterisk/lock.h"
00051 #include "asterisk/app.h"
00052 #include "asterisk/pbx.h"
00053 #include "asterisk/linkedlists.h"
00054 #include "asterisk/module.h"
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 int ast_language_is_prefix;
00065
00066 static AST_LIST_HEAD_STATIC(formats, ast_format);
00067
00068 int __ast_format_register(const struct ast_format *f, struct ast_module *mod)
00069 {
00070 struct ast_format *tmp;
00071
00072 if (AST_LIST_LOCK(&formats)) {
00073 ast_log(LOG_WARNING, "Unable to lock format list\n");
00074 return -1;
00075 }
00076 AST_LIST_TRAVERSE(&formats, tmp, list) {
00077 if (!strcasecmp(f->name, tmp->name)) {
00078 AST_LIST_UNLOCK(&formats);
00079 ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", f->name);
00080 return -1;
00081 }
00082 }
00083 if (!(tmp = ast_calloc(1, sizeof(*tmp)))) {
00084 AST_LIST_UNLOCK(&formats);
00085 return -1;
00086 }
00087 *tmp = *f;
00088 tmp->module = mod;
00089 if (tmp->buf_size) {
00090
00091
00092
00093
00094 struct _test_align { void *a, *b; } p;
00095 int align = (char *)&p.b - (char *)&p.a;
00096 tmp->buf_size = ((f->buf_size + align - 1)/align)*align;
00097 }
00098
00099 memset(&tmp->list, 0, sizeof(tmp->list));
00100
00101 AST_LIST_INSERT_HEAD(&formats, tmp, list);
00102 AST_LIST_UNLOCK(&formats);
00103 if (option_verbose > 1)
00104 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", f->name, f->exts);
00105
00106 return 0;
00107 }
00108
00109 int ast_format_unregister(const char *name)
00110 {
00111 struct ast_format *tmp;
00112 int res = -1;
00113
00114 if (AST_LIST_LOCK(&formats)) {
00115 ast_log(LOG_WARNING, "Unable to lock format list\n");
00116 return -1;
00117 }
00118 AST_LIST_TRAVERSE_SAFE_BEGIN(&formats, tmp, list) {
00119 if (!strcasecmp(name, tmp->name)) {
00120 AST_LIST_REMOVE_CURRENT(&formats, list);
00121 free(tmp);
00122 res = 0;
00123 }
00124 }
00125 AST_LIST_TRAVERSE_SAFE_END
00126 AST_LIST_UNLOCK(&formats);
00127
00128 if (!res) {
00129 if (option_verbose > 1)
00130 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
00131 } else
00132 ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
00133
00134 return res;
00135 }
00136
00137 int ast_stopstream(struct ast_channel *tmp)
00138 {
00139
00140 if (tmp->stream) {
00141 ast_closestream(tmp->stream);
00142 tmp->stream = NULL;
00143 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
00144 ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
00145 }
00146
00147 if (tmp->vstream != NULL) {
00148 ast_closestream(tmp->vstream);
00149 tmp->vstream = NULL;
00150 }
00151 return 0;
00152 }
00153
00154 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
00155 {
00156 int res = -1;
00157 int alt = 0;
00158 if (f->frametype == AST_FRAME_VIDEO) {
00159 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
00160
00161 if (!fs->vfs && fs->filename) {
00162 const char *type = ast_getformatname(f->subclass & ~0x1);
00163 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
00164 ast_log(LOG_DEBUG, "Opened video output file\n");
00165 }
00166 if (fs->vfs)
00167 return ast_writestream(fs->vfs, f);
00168
00169 return 0;
00170 } else {
00171
00172 alt = 1;
00173 }
00174 } else if (f->frametype != AST_FRAME_VOICE) {
00175 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
00176 return -1;
00177 }
00178 if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
00179 res = fs->fmt->write(fs, f);
00180 if (res < 0)
00181 ast_log(LOG_WARNING, "Natural write failed\n");
00182 else if (res > 0)
00183 ast_log(LOG_WARNING, "Huh??\n");
00184 } else {
00185
00186
00187 if (fs->trans && f->subclass != fs->lastwriteformat) {
00188 ast_translator_free_path(fs->trans);
00189 fs->trans = NULL;
00190 }
00191 if (!fs->trans)
00192 fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
00193 if (!fs->trans)
00194 ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n",
00195 fs->fmt->name, ast_getformatname(f->subclass));
00196 else {
00197 struct ast_frame *trf;
00198 fs->lastwriteformat = f->subclass;
00199
00200 trf = ast_translate(fs->trans, f, 0);
00201 if (trf) {
00202 res = fs->fmt->write(fs, trf);
00203 if (res)
00204 ast_log(LOG_WARNING, "Translated frame write failed\n");
00205 } else
00206 res = 0;
00207 }
00208 }
00209 return res;
00210 }
00211
00212 static int copy(const char *infile, const char *outfile)
00213 {
00214 int ifd, ofd, len;
00215 char buf[4096];
00216
00217 if ((ifd = open(infile, O_RDONLY)) < 0) {
00218 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
00219 return -1;
00220 }
00221 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
00222 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
00223 close(ifd);
00224 return -1;
00225 }
00226 while ( (len = read(ifd, buf, sizeof(buf)) ) ) {
00227 int res;
00228 if (len < 0) {
00229 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
00230 break;
00231 }
00232
00233 res = write(ofd, buf, len);
00234 if (res != len) {
00235 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
00236 len = -1;
00237 break;
00238 }
00239 }
00240 close(ifd);
00241 close(ofd);
00242 if (len < 0) {
00243 unlink(outfile);
00244 return -1;
00245 }
00246 return 0;
00247 }
00248
00249
00250
00251
00252
00253
00254
00255 static char *build_filename(const char *filename, const char *ext)
00256 {
00257 char *fn = NULL;
00258
00259 if (!strcmp(ext, "wav49"))
00260 ext = "WAV";
00261
00262 if (filename[0] == '/')
00263 asprintf(&fn, "%s.%s", filename, ext);
00264 else
00265 asprintf(&fn, "%s/sounds/%s.%s",
00266 ast_config_AST_DATA_DIR, filename, ext);
00267 return fn;
00268 }
00269
00270
00271
00272 static int exts_compare(const char *exts, const char *type)
00273 {
00274 char tmp[256];
00275 char *stringp = tmp, *ext;
00276
00277 ast_copy_string(tmp, exts, sizeof(tmp));
00278 while ((ext = strsep(&stringp, "|"))) {
00279 if (!strcmp(ext, type))
00280 return 1;
00281 }
00282
00283 return 0;
00284 }
00285
00286 static struct ast_filestream *get_filestream(struct ast_format *fmt, FILE *bfile)
00287 {
00288 struct ast_filestream *s;
00289
00290 int l = sizeof(*s) + fmt->buf_size + fmt->desc_size;
00291 if ( (s = ast_calloc(1, l)) == NULL)
00292 return NULL;
00293 s->fmt = fmt;
00294 s->f = bfile;
00295
00296 if (fmt->desc_size)
00297 s->private = ((char *)(s+1)) + fmt->buf_size;
00298 if (fmt->buf_size)
00299 s->buf = (char *)(s+1);
00300 s->fr.src = fmt->name;
00301 return s;
00302 }
00303
00304
00305
00306
00307
00308 enum wrap_fn { WRAP_OPEN, WRAP_REWRITE };
00309
00310 static int fn_wrapper(struct ast_filestream *s, const char *comment, enum wrap_fn mode)
00311 {
00312 struct ast_format *f = s->fmt;
00313 int ret = -1;
00314
00315 if (mode == WRAP_OPEN && f->open && f->open(s))
00316 ast_log(LOG_WARNING, "Unable to open format %s\n", f->name);
00317 else if (mode == WRAP_REWRITE && f->rewrite && f->rewrite(s, comment))
00318 ast_log(LOG_WARNING, "Unable to rewrite format %s\n", f->name);
00319 else {
00320
00321 ast_module_ref(f->module);
00322 ret = 0;
00323 }
00324 return ret;
00325 }
00326
00327 static int rewrite_wrapper(struct ast_filestream *s, const char *comment)
00328 {
00329 return fn_wrapper(s, comment, WRAP_REWRITE);
00330 }
00331
00332 static int open_wrapper(struct ast_filestream *s)
00333 {
00334 return fn_wrapper(s, NULL, WRAP_OPEN);
00335 }
00336
00337 enum file_action {
00338 ACTION_EXISTS = 1,
00339 ACTION_DELETE,
00340 ACTION_RENAME,
00341 ACTION_OPEN,
00342 ACTION_COPY
00343 };
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354 static int ast_filehelper(const char *filename, const void *arg2, const char *fmt, const enum file_action action)
00355 {
00356 struct ast_format *f;
00357 int res = (action == ACTION_EXISTS) ? 0 : -1;
00358
00359 if (AST_LIST_LOCK(&formats)) {
00360 ast_log(LOG_WARNING, "Unable to lock format list\n");
00361 return res;
00362 }
00363
00364 AST_LIST_TRAVERSE(&formats, f, list) {
00365 char *stringp, *ext = NULL;
00366
00367 if (fmt && !exts_compare(f->exts, fmt))
00368 continue;
00369
00370
00371
00372
00373
00374 stringp = ast_strdupa(f->exts);
00375 while ( (ext = strsep(&stringp, "|")) ) {
00376 struct stat st;
00377 char *fn = build_filename(filename, ext);
00378
00379 if (fn == NULL)
00380 continue;
00381
00382 if ( stat(fn, &st) ) {
00383 free(fn);
00384 continue;
00385 }
00386
00387
00388
00389 if (action == ACTION_OPEN) {
00390 struct ast_channel *chan = (struct ast_channel *)arg2;
00391 FILE *bfile;
00392 struct ast_filestream *s;
00393
00394 if ( !(chan->writeformat & f->format) &&
00395 !(f->format >= AST_FORMAT_MAX_AUDIO && fmt)) {
00396 free(fn);
00397 continue;
00398 }
00399 if ( (bfile = fopen(fn, "r")) == NULL) {
00400 free(fn);
00401 continue;
00402 }
00403 s = get_filestream(f, bfile);
00404 if (!s) {
00405 fclose(bfile);
00406 free(fn);
00407 continue;
00408 }
00409 if (open_wrapper(s)) {
00410 fclose(bfile);
00411 free(fn);
00412 free(s);
00413 continue;
00414 }
00415
00416 res = 1;
00417 s->lasttimeout = -1;
00418 s->fmt = f;
00419 s->trans = NULL;
00420 s->filename = NULL;
00421 if (s->fmt->format < AST_FORMAT_MAX_AUDIO) {
00422 if (chan->stream)
00423 ast_closestream(chan->stream);
00424 chan->stream = s;
00425 } else {
00426 if (chan->vstream)
00427 ast_closestream(chan->vstream);
00428 chan->vstream = s;
00429 }
00430 free(fn);
00431 break;
00432 }
00433 switch (action) {
00434 case ACTION_OPEN:
00435 break;
00436
00437 case ACTION_EXISTS:
00438 res |= f->format;
00439 break;
00440
00441 case ACTION_DELETE:
00442 if ( (res = unlink(fn)) )
00443 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
00444 break;
00445
00446 case ACTION_RENAME:
00447 case ACTION_COPY: {
00448 char *nfn = build_filename((const char *)arg2, ext);
00449 if (!nfn)
00450 ast_log(LOG_WARNING, "Out of memory\n");
00451 else {
00452 res = action == ACTION_COPY ? copy(fn, nfn) : rename(fn, nfn);
00453 if (res)
00454 ast_log(LOG_WARNING, "%s(%s,%s) failed: %s\n",
00455 action == ACTION_COPY ? "copy" : "rename",
00456 fn, nfn, strerror(errno));
00457 free(nfn);
00458 }
00459 }
00460 break;
00461
00462 default:
00463 ast_log(LOG_WARNING, "Unknown helper %d\n", action);
00464 }
00465 free(fn);
00466 }
00467 }
00468 AST_LIST_UNLOCK(&formats);
00469 return res;
00470 }
00471
00472
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483 static int fileexists_core(const char *filename, const char *fmt, const char *preflang,
00484 char *buf, int buflen)
00485 {
00486 int res = -1;
00487 int langlen;
00488 const char *c = strrchr(filename, '/');
00489 int offset = c ? c - filename + 1 : 0;
00490
00491 if (preflang == NULL)
00492 preflang = "";
00493 langlen = strlen(preflang);
00494
00495 if (buflen < langlen + strlen(filename) + 2) {
00496 ast_log(LOG_WARNING, "buffer too small\n");
00497 buf[0] = '\0';
00498 buf = alloca(langlen + strlen(filename) + 2);
00499 }
00500 if (buf == NULL)
00501 return 0;
00502 buf[0] = '\0';
00503 for (;;) {
00504 if (ast_language_is_prefix) {
00505 if (langlen) {
00506 strcpy(buf, preflang);
00507 buf[langlen] = '/';
00508 strcpy(buf + langlen + 1, filename);
00509 } else
00510 strcpy(buf, filename);
00511 } else {
00512 strcpy(buf, filename);
00513 if (langlen) {
00514
00515 strcpy(buf + offset, preflang);
00516 sprintf(buf + offset + langlen, "/%s", filename + offset);
00517 }
00518 }
00519 res = ast_filehelper(buf, NULL, fmt, ACTION_EXISTS);
00520 if (res > 0)
00521 break;
00522 if (langlen == 0)
00523 break;
00524 if (preflang[langlen] == '_')
00525 langlen = 0;
00526 else
00527 langlen = (c = strchr(preflang, '_')) ? c - preflang : 0;
00528 }
00529 return res;
00530 }
00531
00532 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
00533 {
00534 return ast_openstream_full(chan, filename, preflang, 0);
00535 }
00536
00537 struct ast_filestream *ast_openstream_full(struct ast_channel *chan, const char *filename, const char *preflang, int asis)
00538 {
00539
00540
00541
00542
00543
00544 int fmts, res, buflen;
00545 char *buf;
00546
00547 if (!asis) {
00548
00549 ast_stopstream(chan);
00550 if (chan->generator)
00551 ast_deactivate_generator(chan);
00552 }
00553 if (preflang == NULL)
00554 preflang = "";
00555 buflen = strlen(preflang) + strlen(filename) + 2;
00556 buf = alloca(buflen);
00557 if (buf == NULL)
00558 return NULL;
00559 fmts = fileexists_core(filename, NULL, preflang, buf, buflen);
00560 if (fmts > 0)
00561 fmts &= AST_FORMAT_AUDIO_MASK;
00562 if (fmts < 1) {
00563 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
00564 return NULL;
00565 }
00566 chan->oldwriteformat = chan->writeformat;
00567
00568 res = ast_set_write_format(chan, fmts);
00569 res = ast_filehelper(buf, chan, NULL, ACTION_OPEN);
00570 if (res >= 0)
00571 return chan->stream;
00572 return NULL;
00573 }
00574
00575 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
00576 {
00577
00578
00579
00580 unsigned int format;
00581 char *buf;
00582 int buflen;
00583
00584 if (preflang == NULL)
00585 preflang = "";
00586 buflen = strlen(preflang) + strlen(filename) + 2;
00587 buf = alloca(buflen);
00588 if (buf == NULL)
00589 return NULL;
00590
00591 for (format = AST_FORMAT_MAX_AUDIO << 1; format <= AST_FORMAT_MAX_VIDEO; format = format << 1) {
00592 int fd;
00593 const char *fmt;
00594
00595 if (!(chan->nativeformats & format))
00596 continue;
00597 fmt = ast_getformatname(format);
00598 if ( fileexists_core(filename, fmt, preflang, buf, buflen) < 1)
00599 continue;
00600 fd = ast_filehelper(buf, chan, fmt, ACTION_OPEN);
00601 if (fd >= 0)
00602 return chan->vstream;
00603 ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
00604 }
00605 return NULL;
00606 }
00607
00608 struct ast_frame *ast_readframe(struct ast_filestream *s)
00609 {
00610 struct ast_frame *f = NULL;
00611 int whennext = 0;
00612 if (s && s->fmt)
00613 f = s->fmt->read(s, &whennext);
00614 return f;
00615 }
00616
00617 static int ast_readaudio_callback(void *data)
00618 {
00619 struct ast_filestream *s = data;
00620 int whennext = 0;
00621
00622 while(!whennext) {
00623 struct ast_frame *fr = s->fmt->read(s, &whennext);
00624 if (!fr || ast_write(s->owner, fr) ) {
00625 if (fr)
00626 ast_log(LOG_WARNING, "Failed to write frame\n");
00627 s->owner->streamid = -1;
00628 #ifdef HAVE_ZAPTEL
00629 ast_settimeout(s->owner, 0, NULL, NULL);
00630 #endif
00631 return 0;
00632 }
00633 }
00634 if (whennext != s->lasttimeout) {
00635 #ifdef HAVE_ZAPTEL
00636 if (s->owner->timingfd > -1)
00637 ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
00638 else
00639 #endif
00640 s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
00641 s->lasttimeout = whennext;
00642 return 0;
00643 }
00644 return 1;
00645 }
00646
00647 static int ast_readvideo_callback(void *data)
00648 {
00649 struct ast_filestream *s = data;
00650 int whennext = 0;
00651
00652 while (!whennext) {
00653 struct ast_frame *fr = s->fmt->read(s, &whennext);
00654 if (!fr || ast_write(s->owner, fr)) {
00655 if (fr)
00656 ast_log(LOG_WARNING, "Failed to write frame\n");
00657 s->owner->vstreamid = -1;
00658 return 0;
00659 }
00660 }
00661 if (whennext != s->lasttimeout) {
00662 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
00663 s->lasttimeout = whennext;
00664 return 0;
00665 }
00666 return 1;
00667 }
00668
00669 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
00670 {
00671 s->owner = chan;
00672 return 0;
00673 }
00674
00675 int ast_playstream(struct ast_filestream *s)
00676 {
00677 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
00678 ast_readaudio_callback(s);
00679 else
00680 ast_readvideo_callback(s);
00681 return 0;
00682 }
00683
00684 int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
00685 {
00686 return fs->fmt->seek(fs, sample_offset, whence);
00687 }
00688
00689 int ast_truncstream(struct ast_filestream *fs)
00690 {
00691 return fs->fmt->trunc(fs);
00692 }
00693
00694 off_t ast_tellstream(struct ast_filestream *fs)
00695 {
00696 return fs->fmt->tell(fs);
00697 }
00698
00699 int ast_stream_fastforward(struct ast_filestream *fs, off_t ms)
00700 {
00701 return ast_seekstream(fs, ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
00702 }
00703
00704 int ast_stream_rewind(struct ast_filestream *fs, off_t ms)
00705 {
00706 return ast_seekstream(fs, -ms * DEFAULT_SAMPLES_PER_MS, SEEK_CUR);
00707 }
00708
00709 int ast_closestream(struct ast_filestream *f)
00710 {
00711 char *cmd = NULL;
00712 size_t size = 0;
00713
00714 if (f->owner) {
00715 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
00716 f->owner->stream = NULL;
00717 if (f->owner->streamid > -1)
00718 ast_sched_del(f->owner->sched, f->owner->streamid);
00719 f->owner->streamid = -1;
00720 #ifdef HAVE_ZAPTEL
00721 ast_settimeout(f->owner, 0, NULL, NULL);
00722 #endif
00723 } else {
00724 f->owner->vstream = NULL;
00725 if (f->owner->vstreamid > -1)
00726 ast_sched_del(f->owner->sched, f->owner->vstreamid);
00727 f->owner->vstreamid = -1;
00728 }
00729 }
00730
00731 if (f->trans)
00732 ast_translator_free_path(f->trans);
00733
00734 if (f->realfilename && f->filename) {
00735 size = strlen(f->filename) + strlen(f->realfilename) + 15;
00736 cmd = alloca(size);
00737 memset(cmd,0,size);
00738 snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
00739 ast_safe_system(cmd);
00740 }
00741
00742 if (f->filename)
00743 free(f->filename);
00744 if (f->realfilename)
00745 free(f->realfilename);
00746 if (f->fmt->close)
00747 f->fmt->close(f);
00748 fclose(f->f);
00749 if (f->vfs)
00750 ast_closestream(f->vfs);
00751 ast_module_unref(f->fmt->module);
00752 free(f);
00753 return 0;
00754 }
00755
00756
00757
00758
00759
00760 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
00761 {
00762 char *buf;
00763 int buflen;
00764
00765 if (preflang == NULL)
00766 preflang = "";
00767 buflen = strlen(preflang) + strlen(filename) + 2;
00768 buf = alloca(buflen);
00769 if (buf == NULL)
00770 return 0;
00771 return fileexists_core(filename, fmt, preflang, buf, buflen);
00772 }
00773
00774 int ast_filedelete(const char *filename, const char *fmt)
00775 {
00776 return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
00777 }
00778
00779 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
00780 {
00781 return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
00782 }
00783
00784 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
00785 {
00786 return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
00787 }
00788
00789 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
00790 {
00791 struct ast_filestream *fs;
00792 struct ast_filestream *vfs=NULL;
00793 char fmt[256];
00794
00795 fs = ast_openstream(chan, filename, preflang);
00796 if (fs)
00797 vfs = ast_openvstream(chan, filename, preflang);
00798 if (vfs)
00799 ast_log(LOG_DEBUG, "Ooh, found a video stream, too, format %s\n", ast_getformatname(vfs->fmt->format));
00800 if (fs){
00801 if (ast_applystream(chan, fs))
00802 return -1;
00803 if (vfs && ast_applystream(chan, vfs))
00804 return -1;
00805 ast_playstream(fs);
00806 if (vfs)
00807 ast_playstream(vfs);
00808 if (option_verbose > 2)
00809 ast_verbose(VERBOSE_PREFIX_3 "<%s> Playing '%s' (language '%s')\n", chan->name, filename, preflang ? preflang : "default");
00810
00811 return 0;
00812 }
00813 ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname_multiple(fmt, sizeof(fmt), chan->nativeformats), strerror(errno));
00814 return -1;
00815 }
00816
00817 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
00818 {
00819 FILE *bfile;
00820 struct ast_format *f;
00821 struct ast_filestream *fs = NULL;
00822 char *fn;
00823
00824 if (AST_LIST_LOCK(&formats)) {
00825 ast_log(LOG_WARNING, "Unable to lock format list\n");
00826 return NULL;
00827 }
00828
00829 AST_LIST_TRAVERSE(&formats, f, list) {
00830 fs = NULL;
00831 if (!exts_compare(f->exts, type))
00832 continue;
00833
00834 fn = build_filename(filename, type);
00835 errno = 0;
00836 bfile = fopen(fn, "r");
00837 if (!bfile || (fs = get_filestream(f, bfile)) == NULL ||
00838 open_wrapper(fs) ) {
00839 ast_log(LOG_WARNING, "Unable to open %s\n", fn);
00840 if (fs)
00841 ast_free(fs);
00842 if (bfile)
00843 fclose(bfile);
00844 free(fn);
00845 continue;
00846 }
00847
00848 fs->trans = NULL;
00849 fs->fmt = f;
00850 fs->flags = flags;
00851 fs->mode = mode;
00852 fs->filename = strdup(filename);
00853 fs->vfs = NULL;
00854 break;
00855 }
00856
00857 AST_LIST_UNLOCK(&formats);
00858 if (!fs)
00859 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00860
00861 return fs;
00862 }
00863
00864 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
00865 {
00866 int fd, myflags = 0;
00867
00868 FILE *bfile = NULL;
00869 struct ast_format *f;
00870 struct ast_filestream *fs = NULL;
00871 char *buf = NULL;
00872 size_t size = 0;
00873 int format_found = 0;
00874
00875 if (AST_LIST_LOCK(&formats)) {
00876 ast_log(LOG_WARNING, "Unable to lock format list\n");
00877 return NULL;
00878 }
00879
00880
00881
00882 if (flags & O_APPEND) {
00883 flags &= ~O_APPEND;
00884 } else {
00885 myflags = O_TRUNC;
00886 }
00887
00888 myflags |= O_WRONLY | O_CREAT;
00889
00890
00891
00892
00893 AST_LIST_TRAVERSE(&formats, f, list) {
00894 char *fn, *orig_fn = NULL;
00895 if (fs)
00896 break;
00897
00898 if (!exts_compare(f->exts, type))
00899 continue;
00900 else
00901 format_found = 1;
00902
00903 fn = build_filename(filename, type);
00904 fd = open(fn, flags | myflags, mode);
00905 if (fd > -1) {
00906
00907 bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
00908 if (!bfile) {
00909 ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
00910 close(fd);
00911 fd = -1;
00912 }
00913 }
00914
00915 if (ast_opt_cache_record_files && (fd > -1)) {
00916 char *c;
00917
00918 fclose(bfile);
00919
00920
00921
00922
00923 orig_fn = ast_strdupa(fn);
00924 for (c = fn; *c; c++)
00925 if (*c == '/')
00926 *c = '_';
00927
00928 size = strlen(fn) + strlen(record_cache_dir) + 2;
00929 buf = alloca(size);
00930 strcpy(buf, record_cache_dir);
00931 strcat(buf, "/");
00932 strcat(buf, fn);
00933 free(fn);
00934 fn = buf;
00935 fd = open(fn, flags | myflags, mode);
00936 if (fd > -1) {
00937
00938 bfile = fdopen(fd, ((flags | myflags) & O_RDWR) ? "w+" : "w");
00939 if (!bfile) {
00940 ast_log(LOG_WARNING, "Whoa, fdopen failed: %s!\n", strerror(errno));
00941 close(fd);
00942 fd = -1;
00943 }
00944 }
00945 }
00946 if (fd > -1) {
00947 errno = 0;
00948 fs = get_filestream(f, bfile);
00949 if (!fs || rewrite_wrapper(fs, comment)) {
00950 ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
00951 close(fd);
00952 if (orig_fn) {
00953 unlink(fn);
00954 unlink(orig_fn);
00955 }
00956 if (fs)
00957 ast_free(fs);
00958 fs = NULL;
00959 continue;
00960 }
00961 fs->trans = NULL;
00962 fs->fmt = f;
00963 fs->flags = flags;
00964 fs->mode = mode;
00965 if (orig_fn) {
00966 fs->realfilename = strdup(orig_fn);
00967 fs->filename = strdup(fn);
00968 } else {
00969 fs->realfilename = NULL;
00970 fs->filename = strdup(filename);
00971 }
00972 fs->vfs = NULL;
00973
00974 f->seek(fs, 0, SEEK_END);
00975 } else if (errno != EEXIST) {
00976 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
00977 if (orig_fn)
00978 unlink(orig_fn);
00979 }
00980
00981 if (!buf)
00982 free(fn);
00983 }
00984
00985 AST_LIST_UNLOCK(&formats);
00986
00987 if (!format_found)
00988 ast_log(LOG_WARNING, "No such format '%s'\n", type);
00989
00990 return fs;
00991 }
00992
00993
00994
00995
00996 static int waitstream_core(struct ast_channel *c, const char *breakon,
00997 const char *forward, const char *rewind, int skip_ms,
00998 int audiofd, int cmdfd, const char *context)
00999 {
01000 if (!breakon)
01001 breakon = "";
01002 if (!forward)
01003 forward = "";
01004 if (!rewind)
01005 rewind = "";
01006
01007 while (c->stream) {
01008 int res;
01009 int ms = ast_sched_wait(c->sched);
01010 if (ms < 0 && !c->timingfunc) {
01011 ast_stopstream(c);
01012 break;
01013 }
01014 if (ms < 0)
01015 ms = 1000;
01016 if (cmdfd < 0) {
01017 res = ast_waitfor(c, ms);
01018 if (res < 0) {
01019 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
01020 return res;
01021 }
01022 } else {
01023 int outfd;
01024 struct ast_channel *rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
01025 if (!rchan && (outfd < 0) && (ms)) {
01026
01027 if (errno == EINTR)
01028 continue;
01029 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
01030 return -1;
01031 } else if (outfd > -1) {
01032
01033 return 1;
01034 }
01035
01036 res = rchan ? 1 : 0;
01037 }
01038 if (res > 0) {
01039 struct ast_frame *fr = ast_read(c);
01040 if (!fr)
01041 return -1;
01042 switch(fr->frametype) {
01043 case AST_FRAME_DTMF_END:
01044 if (context) {
01045 const char exten[2] = { fr->subclass, '\0' };
01046 if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
01047 res = fr->subclass;
01048 ast_frfree(fr);
01049 return res;
01050 }
01051 } else {
01052 res = fr->subclass;
01053 if (strchr(forward,res)) {
01054 ast_stream_fastforward(c->stream, skip_ms);
01055 } else if (strchr(rewind,res)) {
01056 ast_stream_rewind(c->stream, skip_ms);
01057 } else if (strchr(breakon, res)) {
01058 ast_frfree(fr);
01059 return res;
01060 }
01061 }
01062 break;
01063 case AST_FRAME_CONTROL:
01064 switch(fr->subclass) {
01065 case AST_CONTROL_HANGUP:
01066 case AST_CONTROL_BUSY:
01067 case AST_CONTROL_CONGESTION:
01068 ast_frfree(fr);
01069 return -1;
01070 case AST_CONTROL_RINGING:
01071 case AST_CONTROL_ANSWER:
01072 case AST_CONTROL_VIDUPDATE:
01073 case AST_CONTROL_HOLD:
01074 case AST_CONTROL_UNHOLD:
01075
01076 break;
01077 default:
01078 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01079 }
01080 break;
01081 case AST_FRAME_VOICE:
01082
01083 if (audiofd > -1)
01084 write(audiofd, fr->data, fr->datalen);
01085 default:
01086
01087 break;
01088 }
01089 ast_frfree(fr);
01090 }
01091 ast_sched_runq(c->sched);
01092 }
01093 return (c->_softhangup ? -1 : 0);
01094 }
01095
01096 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
01097 {
01098 return waitstream_core(c, breakon, forward, rewind, ms,
01099 -1 , -1 , NULL );
01100 }
01101
01102 int ast_waitstream(struct ast_channel *c, const char *breakon)
01103 {
01104 return waitstream_core(c, breakon, NULL, NULL, 0, -1, -1, NULL);
01105 }
01106
01107 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
01108 {
01109 return waitstream_core(c, breakon, NULL, NULL, 0,
01110 audiofd, cmdfd, NULL );
01111 }
01112
01113 int ast_waitstream_exten(struct ast_channel *c, const char *context)
01114 {
01115
01116
01117
01118 if (!context)
01119 context = c->context;
01120 return waitstream_core(c, NULL, NULL, NULL, 0,
01121 -1, -1, context);
01122 }
01123
01124
01125
01126
01127
01128
01129 int ast_stream_and_wait(struct ast_channel *chan, const char *file,
01130 const char *language, const char *digits)
01131 {
01132 int res = 0;
01133 if (!ast_strlen_zero(file)) {
01134 res = ast_streamfile(chan, file, language);
01135 if (!res)
01136 res = ast_waitstream(chan, digits);
01137 }
01138 return res;
01139 }
01140
01141 static int show_file_formats(int fd, int argc, char *argv[])
01142 {
01143 #define FORMAT "%-10s %-10s %-20s\n"
01144 #define FORMAT2 "%-10s %-10s %-20s\n"
01145 struct ast_format *f;
01146 int count_fmt = 0;
01147
01148 if (argc != 4)
01149 return RESULT_SHOWUSAGE;
01150 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01151
01152 if (AST_LIST_LOCK(&formats)) {
01153 ast_log(LOG_WARNING, "Unable to lock format list\n");
01154 return -1;
01155 }
01156
01157 AST_LIST_TRAVERSE(&formats, f, list) {
01158 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01159 count_fmt++;
01160 }
01161 AST_LIST_UNLOCK(&formats);
01162 ast_cli(fd, "%d file formats registered.\n", count_fmt);
01163 return RESULT_SUCCESS;
01164 #undef FORMAT
01165 #undef FORMAT2
01166 }
01167
01168 static int show_file_formats_deprecated(int fd, int argc, char *argv[])
01169 {
01170 #define FORMAT "%-10s %-10s %-20s\n"
01171 #define FORMAT2 "%-10s %-10s %-20s\n"
01172 struct ast_format *f;
01173 int count_fmt = 0;
01174
01175 if (argc != 3)
01176 return RESULT_SHOWUSAGE;
01177 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01178
01179 if (AST_LIST_LOCK(&formats)) {
01180 ast_log(LOG_WARNING, "Unable to lock format list\n");
01181 return -1;
01182 }
01183
01184 AST_LIST_TRAVERSE(&formats, f, list) {
01185 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01186 count_fmt++;
01187 }
01188 AST_LIST_UNLOCK(&formats);
01189 ast_cli(fd, "%d file formats registered.\n", count_fmt);
01190 return RESULT_SUCCESS;
01191 #undef FORMAT
01192 #undef FORMAT2
01193 }
01194
01195 char show_file_formats_usage[] =
01196 "Usage: core show file formats\n"
01197 " Displays currently registered file formats (if any)\n";
01198
01199 struct ast_cli_entry cli_show_file_formats_deprecated = {
01200 { "show", "file", "formats" },
01201 show_file_formats_deprecated, NULL,
01202 NULL };
01203
01204 struct ast_cli_entry cli_file[] = {
01205 { { "core", "show", "file", "formats" },
01206 show_file_formats, "Displays file formats",
01207 show_file_formats_usage, NULL, &cli_show_file_formats_deprecated },
01208 };
01209
01210 int ast_file_init(void)
01211 {
01212 ast_cli_register_multiple(cli_file, sizeof(cli_file) / sizeof(struct ast_cli_entry));
01213 return 0;
01214 }