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: 44580 $")
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 case AST_CONTROL_BUSY:
01032 case AST_CONTROL_CONGESTION:
01033 ast_frfree(fr);
01034 return -1;
01035 case AST_CONTROL_RINGING:
01036 case AST_CONTROL_ANSWER:
01037 case AST_CONTROL_VIDUPDATE:
01038
01039 break;
01040 default:
01041 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01042 }
01043 }
01044
01045 ast_frfree(fr);
01046 }
01047 ast_sched_runq(c->sched);
01048 }
01049 return (c->_softhangup ? -1 : 0);
01050 }
01051
01052 int ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
01053 {
01054 int res;
01055 struct ast_frame *fr;
01056
01057 if (!breakon)
01058 breakon = "";
01059 if (!forward)
01060 forward = "";
01061 if (!rewind)
01062 rewind = "";
01063
01064 while(c->stream) {
01065 res = ast_sched_wait(c->sched);
01066 if ((res < 0) && !c->timingfunc) {
01067 ast_stopstream(c);
01068 break;
01069 }
01070 if (res < 0)
01071 res = 1000;
01072 res = ast_waitfor(c, res);
01073 if (res < 0) {
01074 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
01075 return res;
01076 } else
01077 if (res > 0) {
01078 fr = ast_read(c);
01079 if (!fr) {
01080 #if 0
01081 ast_log(LOG_DEBUG, "Got hung up\n");
01082 #endif
01083 return -1;
01084 }
01085
01086 switch(fr->frametype) {
01087 case AST_FRAME_DTMF:
01088 res = fr->subclass;
01089 if (strchr(forward,res)) {
01090 ast_stream_fastforward(c->stream, ms);
01091 } else if (strchr(rewind,res)) {
01092 ast_stream_rewind(c->stream, ms);
01093 } else if (strchr(breakon, res)) {
01094 ast_frfree(fr);
01095 return res;
01096 }
01097 break;
01098 case AST_FRAME_CONTROL:
01099 switch(fr->subclass) {
01100 case AST_CONTROL_HANGUP:
01101 case AST_CONTROL_BUSY:
01102 case AST_CONTROL_CONGESTION:
01103 ast_frfree(fr);
01104 return -1;
01105 case AST_CONTROL_RINGING:
01106 case AST_CONTROL_ANSWER:
01107
01108 break;
01109 default:
01110 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01111 }
01112 }
01113
01114 ast_frfree(fr);
01115 } else
01116 ast_sched_runq(c->sched);
01117
01118
01119 }
01120 return (c->_softhangup ? -1 : 0);
01121 }
01122
01123 int ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
01124 {
01125 int res;
01126 int ms;
01127 int outfd;
01128 struct ast_frame *fr;
01129 struct ast_channel *rchan;
01130
01131 if (!breakon)
01132 breakon = "";
01133
01134 while(c->stream) {
01135 ms = ast_sched_wait(c->sched);
01136 if ((ms < 0) && !c->timingfunc) {
01137 ast_stopstream(c);
01138 break;
01139 }
01140 if (ms < 0)
01141 ms = 1000;
01142 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
01143 if (!rchan && (outfd < 0) && (ms)) {
01144
01145 if (errno == EINTR)
01146 continue;
01147 ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
01148 return -1;
01149 } else if (outfd > -1) {
01150
01151 return 1;
01152 } else if (rchan) {
01153 fr = ast_read(c);
01154 if (!fr) {
01155 #if 0
01156 ast_log(LOG_DEBUG, "Got hung up\n");
01157 #endif
01158 return -1;
01159 }
01160
01161 switch(fr->frametype) {
01162 case AST_FRAME_DTMF:
01163 res = fr->subclass;
01164 if (strchr(breakon, res)) {
01165 ast_frfree(fr);
01166 return res;
01167 }
01168 break;
01169 case AST_FRAME_CONTROL:
01170 switch(fr->subclass) {
01171 case AST_CONTROL_HANGUP:
01172 case AST_CONTROL_BUSY:
01173 case AST_CONTROL_CONGESTION:
01174 ast_frfree(fr);
01175 return -1;
01176 case AST_CONTROL_RINGING:
01177 case AST_CONTROL_ANSWER:
01178
01179 break;
01180 default:
01181 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01182 }
01183 case AST_FRAME_VOICE:
01184
01185 if (audiofd > -1)
01186 write(audiofd, fr->data, fr->datalen);
01187 }
01188
01189 ast_frfree(fr);
01190 }
01191 ast_sched_runq(c->sched);
01192 }
01193 return (c->_softhangup ? -1 : 0);
01194 }
01195
01196 int ast_waitstream_exten(struct ast_channel *c, const char *context)
01197 {
01198
01199
01200
01201 int res;
01202 struct ast_frame *fr;
01203 char exten[AST_MAX_EXTENSION];
01204
01205 if (!context) context = c->context;
01206 while(c->stream) {
01207 res = ast_sched_wait(c->sched);
01208 if ((res < 0) && !c->timingfunc) {
01209 ast_stopstream(c);
01210 break;
01211 }
01212 if (res < 0)
01213 res = 1000;
01214 res = ast_waitfor(c, res);
01215 if (res < 0) {
01216 ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
01217 return res;
01218 } else if (res > 0) {
01219 fr = ast_read(c);
01220 if (!fr) {
01221 #if 0
01222 ast_log(LOG_DEBUG, "Got hung up\n");
01223 #endif
01224 return -1;
01225 }
01226
01227 switch(fr->frametype) {
01228 case AST_FRAME_DTMF:
01229 res = fr->subclass;
01230 snprintf(exten, sizeof(exten), "%c", res);
01231 if (ast_exists_extension(c, context, exten, 1, c->cid.cid_num)) {
01232 ast_frfree(fr);
01233 return res;
01234 }
01235 break;
01236 case AST_FRAME_CONTROL:
01237 switch(fr->subclass) {
01238 case AST_CONTROL_HANGUP:
01239 case AST_CONTROL_BUSY:
01240 case AST_CONTROL_CONGESTION:
01241 ast_frfree(fr);
01242 return -1;
01243 case AST_CONTROL_RINGING:
01244 case AST_CONTROL_ANSWER:
01245
01246 break;
01247 default:
01248 ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
01249 }
01250 }
01251
01252 ast_frfree(fr);
01253 }
01254 ast_sched_runq(c->sched);
01255 }
01256 return (c->_softhangup ? -1 : 0);
01257 }
01258
01259 static int show_file_formats(int fd, int argc, char *argv[])
01260 {
01261 #define FORMAT "%-10s %-10s %-20s\n"
01262 #define FORMAT2 "%-10s %-10s %-20s\n"
01263 struct ast_format *f;
01264 int count_fmt = 0;
01265
01266 if (argc != 3)
01267 return RESULT_SHOWUSAGE;
01268 ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
01269
01270 if (ast_mutex_lock(&formatlock)) {
01271 ast_log(LOG_WARNING, "Unable to lock format list\n");
01272 return -1;
01273 }
01274
01275 f = formats;
01276 while(f) {
01277 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
01278 f = f->next;
01279 count_fmt++;
01280 };
01281 ast_mutex_unlock(&formatlock);
01282 ast_cli(fd, "%d file formats registered.\n", count_fmt);
01283 return RESULT_SUCCESS;
01284 #undef FORMAT
01285 #undef FORMAT2
01286
01287 }
01288
01289 struct ast_cli_entry show_file =
01290 {
01291 { "show", "file", "formats" },
01292 show_file_formats,
01293 "Displays file formats",
01294 "Usage: show file formats\n"
01295 " displays currently registered file formats (if any)\n"
01296 };
01297
01298 int ast_file_init(void)
01299 {
01300 ast_cli_register(&show_file);
01301 return 0;
01302 }