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