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