add missing ~ to ast_parse_allow_deny that was breaking disallow
[asterisk/asterisk.git] / file.c
1 /*
2  * Asterisk -- A telephony toolkit for Linux.
3  *
4  * Generic File Format Support.
5  * 
6  * Copyright (C) 1999, Mark Spencer
7  *
8  * Mark Spencer <markster@linux-support.net>
9  *
10  * This program is free software, distributed under the terms of
11  * the GNU General Public License
12  */
13
14 #include <sys/types.h>
15 #include <asterisk/frame.h>
16 #include <asterisk/file.h>
17 #include <asterisk/cli.h>
18 #include <asterisk/logger.h>
19 #include <asterisk/channel.h>
20 #include <asterisk/sched.h>
21 #include <asterisk/options.h>
22 #include <asterisk/translate.h>
23 #include <asterisk/utils.h>
24 #include <asterisk/lock.h>
25 #include <asterisk/app.h>
26 #include <errno.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <string.h>
30 #include <stdio.h>
31 #include <fcntl.h>
32 #include <dirent.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include "asterisk.h"
36 #include "astconf.h"
37
38 struct ast_format {
39         /* Name of format */
40         char name[80];
41         /* Extensions (separated by | if more than one) 
42            this format can read.  First is assumed for writing (e.g. .mp3) */
43         char exts[80];
44         /* Format of frames it uses/provides (one only) */
45         int format;
46         /* Open an input stream, and start playback */
47         struct ast_filestream * (*open)(int fd);
48         /* Open an output stream, of a given file descriptor and comment it appropriately if applicable */
49         struct ast_filestream * (*rewrite)(int fd, const char *comment);
50         /* Write a frame to a channel */
51         int (*write)(struct ast_filestream *, struct ast_frame *);
52         /* seek num samples into file, whence(think normal seek) */
53         int (*seek)(struct ast_filestream *, long offset, int whence);
54         /* trunc file to current position */
55         int (*trunc)(struct ast_filestream *fs);
56         /* tell current position */
57         long (*tell)(struct ast_filestream *fs);
58         /* Read the next frame from the filestream (if available) and report when to get next one
59                 (in samples) */
60         struct ast_frame * (*read)(struct ast_filestream *, int *whennext);
61         /* Close file, and destroy filestream structure */
62         void (*close)(struct ast_filestream *);
63         /* Retrieve file comment */
64         char * (*getcomment)(struct ast_filestream *);
65         /* Link */
66         struct ast_format *next;
67 };
68
69 struct ast_filestream {
70         /* Everybody reserves a block of AST_RESERVED_POINTERS pointers for us */
71         struct ast_format *fmt;
72         int flags;
73         mode_t mode;
74         char *filename;
75         char *realfilename;
76         /* Video file stream */
77         struct ast_filestream *vfs;
78         /* Transparently translate from another format -- just once */
79         struct ast_trans_pvt *trans;
80         struct ast_tranlator_pvt *tr;
81         int lastwriteformat;
82         int lasttimeout;
83         struct ast_channel *owner;
84 };
85
86 AST_MUTEX_DEFINE_STATIC(formatlock);
87
88 static struct ast_format *formats = NULL;
89
90 int ast_format_register(const char *name, const char *exts, int format,
91                                                 struct ast_filestream * (*open)(int fd),
92                                                 struct ast_filestream * (*rewrite)(int fd, const char *comment),
93                                                 int (*write)(struct ast_filestream *, struct ast_frame *),
94                                                 int (*seek)(struct ast_filestream *, long sample_offset, int whence),
95                                                 int (*trunc)(struct ast_filestream *),
96                                                 long (*tell)(struct ast_filestream *),
97                                                 struct ast_frame * (*read)(struct ast_filestream *, int *whennext),
98                                                 void (*close)(struct ast_filestream *),
99                                                 char * (*getcomment)(struct ast_filestream *))
100 {
101         struct ast_format *tmp;
102         if (ast_mutex_lock(&formatlock)) {
103                 ast_log(LOG_WARNING, "Unable to lock format list\n");
104                 return -1;
105         }
106         tmp = formats;
107         while(tmp) {
108                 if (!strcasecmp(name, tmp->name)) {
109                         ast_mutex_unlock(&formatlock);
110                         ast_log(LOG_WARNING, "Tried to register '%s' format, already registered\n", name);
111                         return -1;
112                 }
113                 tmp = tmp->next;
114         }
115         tmp = malloc(sizeof(struct ast_format));
116         if (!tmp) {
117                 ast_log(LOG_WARNING, "Out of memory\n");
118                 ast_mutex_unlock(&formatlock);
119                 return -1;
120         }
121         strncpy(tmp->name, name, sizeof(tmp->name)-1);
122         strncpy(tmp->exts, exts, sizeof(tmp->exts)-1);
123         tmp->open = open;
124         tmp->rewrite = rewrite;
125         tmp->read = read;
126         tmp->write = write;
127         tmp->seek = seek;
128         tmp->trunc = trunc;
129         tmp->tell = tell;
130         tmp->close = close;
131         tmp->format = format;
132         tmp->getcomment = getcomment;
133         tmp->next = formats;
134         formats = tmp;
135         ast_mutex_unlock(&formatlock);
136         if (option_verbose > 1)
137                 ast_verbose( VERBOSE_PREFIX_2 "Registered file format %s, extension(s) %s\n", name, exts);
138         return 0;
139 }
140
141 int ast_format_unregister(const char *name)
142 {
143         struct ast_format *tmp, *tmpl = NULL;
144         if (ast_mutex_lock(&formatlock)) {
145                 ast_log(LOG_WARNING, "Unable to lock format list\n");
146                 return -1;
147         }
148         tmp = formats;
149         while(tmp) {
150                 if (!strcasecmp(name, tmp->name)) {
151                         if (tmpl) 
152                                 tmpl->next = tmp->next;
153                         else
154                                 formats = tmp->next;
155                         free(tmp);
156                         ast_mutex_unlock(&formatlock);
157                         if (option_verbose > 1)
158                                 ast_verbose( VERBOSE_PREFIX_2 "Unregistered format %s\n", name);
159                         return 0;
160                 }
161                 tmpl = tmp;
162                 tmp = tmp->next;
163         }
164         ast_log(LOG_WARNING, "Tried to unregister format %s, already unregistered\n", name);
165         return -1;
166 }
167
168 int ast_stopstream(struct ast_channel *tmp)
169 {
170         /* Stop a running stream if there is one */
171         if (tmp->vstream)
172                 ast_closestream(tmp->vstream);
173         if (tmp->stream) {
174                 ast_closestream(tmp->stream);
175                 if (tmp->oldwriteformat && ast_set_write_format(tmp, tmp->oldwriteformat))
176                         ast_log(LOG_WARNING, "Unable to restore format back to %d\n", tmp->oldwriteformat);
177         }
178         return 0;
179 }
180
181 int ast_writestream(struct ast_filestream *fs, struct ast_frame *f)
182 {
183         struct ast_frame *trf;
184         int res = -1;
185         int alt=0;
186         if (f->frametype == AST_FRAME_VIDEO) {
187                 if (fs->fmt->format < AST_FORMAT_MAX_AUDIO) {
188                         /* This is the audio portion.  Call the video one... */
189                         if (!fs->vfs && fs->filename) {
190                                 /* XXX Support other video formats XXX */
191                                 const char *type = "h263";
192                                 fs->vfs = ast_writefile(fs->filename, type, NULL, fs->flags, 0, fs->mode);
193                                 ast_log(LOG_DEBUG, "Opened video output file\n");
194                         }
195                         if (fs->vfs)
196                                 return ast_writestream(fs->vfs, f);
197                         /* Ignore */
198                         return 0;                               
199                 } else {
200                         /* Might / might not have mark set */
201                         alt = 1;
202                 }
203         } else if (f->frametype != AST_FRAME_VOICE) {
204                 ast_log(LOG_WARNING, "Tried to write non-voice frame\n");
205                 return -1;
206         }
207         if (((fs->fmt->format | alt) & f->subclass) == f->subclass) {
208                 res =  fs->fmt->write(fs, f);
209                 if (res < 0) 
210                         ast_log(LOG_WARNING, "Natural write failed\n");
211                 if (res > 0)
212                         ast_log(LOG_WARNING, "Huh??\n");
213                 return res;
214         } else {
215                 /* XXX If they try to send us a type of frame that isn't the normal frame, and isn't
216                        the one we've setup a translator for, we do the "wrong thing" XXX */
217                 if (fs->trans && (f->subclass != fs->lastwriteformat)) {
218                         ast_translator_free_path(fs->trans);
219                         fs->trans = NULL;
220                 }
221                 if (!fs->trans) 
222                         fs->trans = ast_translator_build_path(fs->fmt->format, f->subclass);
223                 if (!fs->trans)
224                         ast_log(LOG_WARNING, "Unable to translate to format %s, source format %s\n", fs->fmt->name, ast_getformatname(f->subclass));
225                 else {
226                         fs->lastwriteformat = f->subclass;
227                         res = 0;
228                         /* Get the translated frame but don't consume the original in case they're using it on another stream */
229                         trf = ast_translate(fs->trans, f, 0);
230                         if (trf) {
231                                 res = fs->fmt->write(fs, trf);
232                                 if (res) 
233                                         ast_log(LOG_WARNING, "Translated frame write failed\n");
234                         } else
235                                 res = 0;
236                 }
237                 return res;
238         }
239 }
240
241 static int copy(const char *infile, const char *outfile)
242 {
243         int ifd;
244         int ofd;
245         int res;
246         int len;
247         char buf[4096];
248
249         if ((ifd = open(infile, O_RDONLY)) < 0) {
250                 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
251                 return -1;
252         }
253         if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
254                 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
255                 close(ifd);
256                 return -1;
257         }
258         do {
259                 len = read(ifd, buf, sizeof(buf));
260                 if (len < 0) {
261                         ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
262                         close(ifd);
263                         close(ofd);
264                         unlink(outfile);
265                 }
266                 if (len) {
267                         res = write(ofd, buf, len);
268                         if (res != len) {
269                                 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
270                                 close(ifd);
271                                 close(ofd);
272                                 unlink(outfile);
273                         }
274                 }
275         } while(len);
276         close(ifd);
277         close(ofd);
278         return 0;
279 }
280
281 static char *build_filename(const char *filename, const char *ext)
282 {
283         char *fn;
284         int fnsize = 0;
285         char tmp[AST_CONFIG_MAX_PATH]="";
286
287         snprintf(tmp, sizeof(tmp), "%s/%s", ast_config_AST_VAR_DIR, "sounds");
288         fnsize = strlen(tmp) + strlen(filename) + strlen(ext) + 10;
289         fn = malloc(fnsize);
290         if (fn) {
291                 if (filename[0] == '/') 
292                         snprintf(fn, fnsize, "%s.%s", filename, ext);
293                 else
294                         snprintf(fn, fnsize, "%s/%s.%s", tmp, filename, ext);
295         }
296         return fn;
297         
298 }
299
300 static int exts_compare(const char *exts, const char *type)
301 {
302         char *stringp = NULL, *ext;
303         char tmp[256];
304
305         strncpy(tmp, exts, sizeof(tmp) - 1);
306         stringp = tmp;
307         while ((ext = strsep(&stringp, "|"))) {
308                 if (!strcmp(ext, type)) {
309                         return 1;
310                 }
311         }
312
313         return 0;
314 }
315
316 #define ACTION_EXISTS 1
317 #define ACTION_DELETE 2
318 #define ACTION_RENAME 3
319 #define ACTION_OPEN   4
320 #define ACTION_COPY   5
321
322 static int ast_filehelper(const char *filename, const char *filename2, const char *fmt, int action)
323 {
324         struct stat st;
325         struct ast_format *f;
326         struct ast_filestream *s;
327         int res=0, ret = 0;
328         char *ext=NULL, *exts, *fn, *nfn;
329         struct ast_channel *chan = (struct ast_channel *)filename2;
330         
331         /* Start with negative response */
332         if (action == ACTION_EXISTS)
333                 res = 0;
334         else
335                 res = -1;
336         if (action == ACTION_OPEN)
337                 ret = -1;
338         /* Check for a specific format */
339         if (ast_mutex_lock(&formatlock)) {
340                 ast_log(LOG_WARNING, "Unable to lock format list\n");
341                 if (action == ACTION_EXISTS)
342                         return 0;
343                 else
344                         return -1;
345         }
346         f = formats;
347         while(f) {
348                 if (!fmt || exts_compare(f->exts, fmt)) {
349                         char *stringp=NULL;
350                         exts = strdup(f->exts);
351                         /* Try each kind of extension */
352                         stringp=exts;
353                         ext = strsep(&stringp, "|");
354                         if (!strcmp(ext,"wav49")) {
355                                 ext = "WAV";
356                         }
357                         do {
358                                 fn = build_filename(filename, ext);
359                                 if (fn) {
360                                         res = stat(fn, &st);
361                                         if (!res) {
362                                                 switch(action) {
363                                                 case ACTION_EXISTS:
364                                                         ret |= f->format;
365                                                         break;
366                                                 case ACTION_DELETE:
367                                                         res = unlink(fn);
368                                                         if (res)
369                                                                 ast_log(LOG_WARNING, "unlink(%s) failed: %s\n", fn, strerror(errno));
370                                                         break;
371                                                 case ACTION_RENAME:
372                                                         nfn = build_filename(filename2, ext);
373                                                         if (nfn) {
374                                                                 res = rename(fn, nfn);
375                                                                 if (res)
376                                                                         ast_log(LOG_WARNING, "rename(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
377                                                                 free(nfn);
378                                                         } else
379                                                                 ast_log(LOG_WARNING, "Out of memory\n");
380                                                         break;
381                                                 case ACTION_COPY:
382                                                         nfn = build_filename(filename2, ext);
383                                                         if (nfn) {
384                                                                 res = copy(fn, nfn);
385                                                                 if (res)
386                                                                         ast_log(LOG_WARNING, "copy(%s,%s) failed: %s\n", fn, nfn, strerror(errno));
387                                                                 free(nfn);
388                                                         } else
389                                                                 ast_log(LOG_WARNING, "Out of memory\n");
390                                                         break;
391                                                 case ACTION_OPEN:
392                                                         if ((ret < 0) && ((chan->writeformat & f->format) ||
393                                                                                 ((f->format >= AST_FORMAT_MAX_AUDIO) && fmt))) {
394                                                                 ret = open(fn, O_RDONLY);
395                                                                 if (ret >= 0) {
396                                                                         s = f->open(ret);
397                                                                         if (s) {
398                                                                                 s->lasttimeout = -1;
399                                                                                 s->fmt = f;
400                                                                                 s->trans = NULL;
401                                                                                 s->filename = NULL;
402                                                                                 if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
403                                                                                         chan->stream = s;
404                                                                                 else
405                                                                                         chan->vstream = s;
406                                                                         } else {
407                                                                                 close(ret);
408                                                                                 ast_log(LOG_WARNING, "Unable to open fd on %s\n", fn);
409                                                                         }
410                                                                 } else
411                                                                         ast_log(LOG_WARNING, "Couldn't open file %s\n", fn);
412                                                         }
413                                                         break;
414                                                 default:
415                                                         ast_log(LOG_WARNING, "Unknown helper %d\n", action);
416                                                 }
417                                                 /* Conveniently this logic is the same for all */
418                                                 if (res)
419                                                         break;
420                                         }
421                                         free(fn);
422                                 }
423                                 ext = strsep(&stringp, "|");
424                         } while(ext);
425                         free(exts);
426                 }
427                 f = f->next;
428         }
429         ast_mutex_unlock(&formatlock);
430         if ((action == ACTION_EXISTS) || (action == ACTION_OPEN))
431                 res = ret ? ret : -1;
432         return res;
433 }
434
435 struct ast_filestream *ast_openstream(struct ast_channel *chan, const char *filename, const char *preflang)
436 {
437         /* This is a fairly complex routine.  Essentially we should do 
438            the following:
439            
440            1) Find which file handlers produce our type of format.
441            2) Look for a filename which it can handle.
442            3) If we find one, then great.  
443            4) If not, see what files are there
444            5) See what we can actually support
445            6) Choose the one with the least costly translator path and
446                set it up.
447                    
448         */
449         int fd = -1;
450         int fmts = -1;
451         char filename2[256]="";
452         char filename3[256]="";
453         char *endpart;
454         int res;
455         ast_stopstream(chan);
456         /* do this first, otherwise we detect the wrong writeformat */
457         if (chan->generator)
458                 ast_deactivate_generator(chan);
459         if (preflang && !ast_strlen_zero(preflang)) {
460                 strncpy(filename3, filename, sizeof(filename3) - 1);
461                 endpart = strrchr(filename3, '/');
462                 if (endpart) {
463                         *endpart = '\0';
464                         endpart++;
465                         snprintf(filename2, sizeof(filename2), "%s/%s/%s", filename3, preflang, endpart);
466                 } else
467                         snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
468                 fmts = ast_fileexists(filename2, NULL, NULL);
469         }
470         if (fmts < 1) {
471                 strncpy(filename2, filename, sizeof(filename2)-1);
472                 fmts = ast_fileexists(filename2, NULL, NULL);
473         }
474         if (fmts < 1) {
475                 ast_log(LOG_WARNING, "File %s does not exist in any format\n", filename);
476                 return NULL;
477         }
478         chan->oldwriteformat = chan->writeformat;
479         /* Set the channel to a format we can work with */
480         res = ast_set_write_format(chan, fmts);
481         
482         fd = ast_filehelper(filename2, (char *)chan, NULL, ACTION_OPEN);
483         if (fd >= 0)
484                 return chan->stream;
485         return NULL;
486 }
487
488 struct ast_filestream *ast_openvstream(struct ast_channel *chan, const char *filename, const char *preflang)
489 {
490         /* This is a fairly complex routine.  Essentially we should do 
491            the following:
492            
493            1) Find which file handlers produce our type of format.
494            2) Look for a filename which it can handle.
495            3) If we find one, then great.  
496            4) If not, see what files are there
497            5) See what we can actually support
498            6) Choose the one with the least costly translator path and
499                set it up.
500                    
501         */
502         int fd = -1;
503         int fmts = -1;
504         char filename2[256];
505         char lang2[MAX_LANGUAGE];
506         /* XXX H.263 only XXX */
507         char *fmt = "h263";
508         if (preflang && !ast_strlen_zero(preflang)) {
509                 snprintf(filename2, sizeof(filename2), "%s/%s", preflang, filename);
510                 fmts = ast_fileexists(filename2, fmt, NULL);
511                 if (fmts < 1) {
512                         strncpy(lang2, preflang, sizeof(lang2)-1);
513                         snprintf(filename2, sizeof(filename2), "%s/%s", lang2, filename);
514                         fmts = ast_fileexists(filename2, fmt, NULL);
515                 }
516         }
517         if (fmts < 1) {
518                 strncpy(filename2, filename, sizeof(filename2)-1);
519                 fmts = ast_fileexists(filename2, fmt, NULL);
520         }
521         if (fmts < 1) {
522                 return NULL;
523         }
524         fd = ast_filehelper(filename2, (char *)chan, fmt, ACTION_OPEN);
525         if (fd >= 0)
526                 return chan->vstream;
527         ast_log(LOG_WARNING, "File %s has video but couldn't be opened\n", filename);
528         return NULL;
529 }
530
531 struct ast_frame *ast_readframe(struct ast_filestream *s)
532 {
533         struct ast_frame *f = NULL;
534         int whennext = 0;       
535         if (s && s->fmt)
536                 f = s->fmt->read(s, &whennext);
537         return f;
538 }
539
540 static int ast_readaudio_callback(void *data)
541 {
542         struct ast_filestream *s = data;
543         struct ast_frame *fr;
544         int whennext = 0;
545
546         while(!whennext) {
547                 fr = s->fmt->read(s, &whennext);
548                 if (fr) {
549                         if (ast_write(s->owner, fr)) {
550                                 ast_log(LOG_WARNING, "Failed to write frame\n");
551                                 s->owner->streamid = -1;
552 #ifdef ZAPTEL_OPTIMIZATIONS
553                                 ast_settimeout(s->owner, 0, NULL, NULL);
554 #endif                  
555                                 return 0;
556                         }
557                 } else {
558                         /* Stream has finished */
559                         s->owner->streamid = -1;
560 #ifdef ZAPTEL_OPTIMIZATIONS
561                         ast_settimeout(s->owner, 0, NULL, NULL);
562 #endif                  
563                         return 0;
564                 }
565         }
566         if (whennext != s->lasttimeout) {
567 #ifdef ZAPTEL_OPTIMIZATIONS
568                 if (s->owner->timingfd > -1)
569                         ast_settimeout(s->owner, whennext, ast_readaudio_callback, s);
570                 else
571 #endif          
572                         s->owner->streamid = ast_sched_add(s->owner->sched, whennext/8, ast_readaudio_callback, s);
573                 s->lasttimeout = whennext;
574                 return 0;
575         }
576         return 1;
577 }
578
579 static int ast_readvideo_callback(void *data)
580 {
581         struct ast_filestream *s = data;
582         struct ast_frame *fr;
583         int whennext = 0;
584
585         while(!whennext) {
586                 fr = s->fmt->read(s, &whennext);
587                 if (fr) {
588                         if (ast_write(s->owner, fr)) {
589                                 ast_log(LOG_WARNING, "Failed to write frame\n");
590                                 s->owner->vstreamid = -1;
591                                 return 0;
592                         }
593                 } else {
594                         /* Stream has finished */
595                         s->owner->vstreamid = -1;
596                         return 0;
597                 }
598         }
599         if (whennext != s->lasttimeout) {
600                 s->owner->vstreamid = ast_sched_add(s->owner->sched, whennext/8, ast_readvideo_callback, s);
601                 s->lasttimeout = whennext;
602                 return 0;
603         }
604         return 1;
605 }
606
607 int ast_applystream(struct ast_channel *chan, struct ast_filestream *s)
608 {
609         s->owner = chan;
610         return 0;
611 }
612
613 int ast_playstream(struct ast_filestream *s)
614 {
615         if (s->fmt->format < AST_FORMAT_MAX_AUDIO)
616                 ast_readaudio_callback(s);
617         else
618                 ast_readvideo_callback(s);
619         return 0;
620 }
621
622 int ast_seekstream(struct ast_filestream *fs, long sample_offset, int whence)
623 {
624         return fs->fmt->seek(fs, sample_offset, whence);
625 }
626
627 int ast_truncstream(struct ast_filestream *fs)
628 {
629         return fs->fmt->trunc(fs);
630 }
631
632 long ast_tellstream(struct ast_filestream *fs)
633 {
634         return fs->fmt->tell(fs);
635 }
636
637 int ast_stream_fastforward(struct ast_filestream *fs, long ms)
638 {
639         /* I think this is right, 8000 samples per second, 1000 ms a second so 8
640          * samples per ms  */
641         long samples = ms * 8;
642         return ast_seekstream(fs, samples, SEEK_CUR);
643 }
644
645 int ast_stream_rewind(struct ast_filestream *fs, long ms)
646 {
647         long samples = ms * 8;
648         samples = samples * -1;
649         return ast_seekstream(fs, samples, SEEK_CUR);
650 }
651
652 int ast_closestream(struct ast_filestream *f)
653 {
654         char *cmd = NULL;
655         size_t size = 0;
656         /* Stop a running stream if there is one */
657         if (f->owner) {
658                 if (f->fmt->format < AST_FORMAT_MAX_AUDIO) {
659                         f->owner->stream = NULL;
660                         if (f->owner->streamid > -1)
661                                 ast_sched_del(f->owner->sched, f->owner->streamid);
662                         f->owner->streamid = -1;
663 #ifdef ZAPTEL_OPTIMIZATIONS
664                         ast_settimeout(f->owner, 0, NULL, NULL);
665 #endif                  
666                 } else {
667                         f->owner->vstream = NULL;
668                         if (f->owner->vstreamid > -1)
669                                 ast_sched_del(f->owner->sched, f->owner->vstreamid);
670                         f->owner->vstreamid = -1;
671                 }
672         }
673         /* destroy the translator on exit */
674         if (f->trans) {
675                 ast_translator_free_path(f->trans);
676                 f->trans = NULL;
677         }
678
679         if (f->realfilename && f->filename) {
680                         size = strlen(f->filename) + strlen(f->realfilename) + 15;
681                         cmd = alloca(size);
682                         memset(cmd,0,size);
683                         snprintf(cmd,size,"/bin/mv -f %s %s",f->filename,f->realfilename);
684                         ast_safe_system(cmd);
685         }
686
687         if (f->filename) {
688                 free(f->filename);
689                 f->filename = NULL;
690         }
691         if (f->realfilename) {
692                 free(f->realfilename);
693                 f->realfilename = NULL;
694         }
695         f->fmt->close(f);
696         return 0;
697 }
698
699
700 int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
701 {
702         char filename2[256];
703         char tmp[256];
704         char *postfix;
705         char *prefix;
706         char *c;
707         char lang2[MAX_LANGUAGE];
708         int res = -1;
709         if (preflang && !ast_strlen_zero(preflang)) {
710                 /* Insert the language between the last two parts of the path */
711                 strncpy(tmp, filename, sizeof(tmp) - 1);
712                 c = strrchr(tmp, '/');
713                 if (c) {
714                         *c = '\0';
715                         postfix = c+1;
716                         prefix = tmp;
717                 } else {
718                         postfix = tmp;
719                         prefix="";
720                 }
721                 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, preflang, postfix);
722                 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
723                 if (res < 1) {
724                         char *stringp=NULL;
725                         strncpy(lang2, preflang, sizeof(lang2)-1);
726                         stringp=lang2;
727                         strsep(&stringp, "_");
728                         if (strcmp(lang2, preflang)) {
729                                 snprintf(filename2, sizeof(filename2), "%s/%s/%s", prefix, lang2, postfix);
730                                 res = ast_filehelper(filename2, NULL, fmt, ACTION_EXISTS);
731                         }
732                 }
733         }
734         if (res < 1) {
735                 res = ast_filehelper(filename, NULL, fmt, ACTION_EXISTS);
736         }
737         return res;
738 }
739
740 int ast_filedelete(const char *filename, const char *fmt)
741 {
742         return ast_filehelper(filename, NULL, fmt, ACTION_DELETE);
743 }
744
745 int ast_filerename(const char *filename, const char *filename2, const char *fmt)
746 {
747         return ast_filehelper(filename, filename2, fmt, ACTION_RENAME);
748 }
749
750 int ast_filecopy(const char *filename, const char *filename2, const char *fmt)
751 {
752         return ast_filehelper(filename, filename2, fmt, ACTION_COPY);
753 }
754
755 int ast_streamfile(struct ast_channel *chan, const char *filename, const char *preflang)
756 {
757         struct ast_filestream *fs;
758         struct ast_filestream *vfs;
759
760         fs = ast_openstream(chan, filename, preflang);
761         vfs = ast_openvstream(chan, filename, preflang);
762         if (vfs)
763                 ast_log(LOG_DEBUG, "Ooh, found a video stream, too\n");
764         if (fs){
765                 if (ast_applystream(chan, fs))
766                         return -1;
767                 if (vfs && ast_applystream(chan, vfs))
768                         return -1;
769                 if (ast_playstream(fs))
770                         return -1;
771                 if (vfs && ast_playstream(vfs))
772                         return -1;
773 #if 1
774                 if (option_verbose > 2)
775                         ast_verbose(VERBOSE_PREFIX_3 "Playing '%s' (language '%s')\n", filename, preflang ? preflang : "default");
776 #endif
777                 return 0;
778         }
779         ast_log(LOG_WARNING, "Unable to open %s (format %s): %s\n", filename, ast_getformatname(chan->nativeformats), strerror(errno));
780         return -1;
781 }
782
783 struct ast_filestream *ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
784 {
785         int fd,myflags = 0;
786         struct ast_format *f;
787         struct ast_filestream *fs=NULL;
788         char *fn;
789         char *ext;
790         if (ast_mutex_lock(&formatlock)) {
791                 ast_log(LOG_WARNING, "Unable to lock format list\n");
792                 return NULL;
793         }
794         f = formats;
795         while(f) {
796                 if (exts_compare(f->exts, type)) {
797                         char *stringp=NULL;
798                         /* XXX Implement check XXX */
799                         ext = strdup(f->exts);
800                         stringp=ext;
801                         ext = strsep(&stringp, "|");
802                         fn = build_filename(filename, ext);
803                         fd = open(fn, flags | myflags);
804                         if (fd >= 0) {
805                                 errno = 0;
806                                 if ((fs = f->open(fd))) {
807                                         fs->trans = NULL;
808                                         fs->fmt = f;
809                                         fs->flags = flags;
810                                         fs->mode = mode;
811                                         fs->filename = strdup(filename);
812                                         fs->vfs = NULL;
813                                 } else {
814                                         ast_log(LOG_WARNING, "Unable to open %s\n", fn);
815                                         close(fd);
816                                         unlink(fn);
817                                 }
818                         } else if (errno != EEXIST)
819                                 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
820                         free(fn);
821                         free(ext);
822                         break;
823                 }
824                 f = f->next;
825         }
826         ast_mutex_unlock(&formatlock);
827         if (!f) 
828                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
829         return fs;
830 }
831
832 struct ast_filestream *ast_writefile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
833 {
834         int fd,myflags = 0;
835         struct ast_format *f;
836         struct ast_filestream *fs=NULL;
837         char *fn,*orig_fn=NULL;
838         char *ext;
839         char *buf=NULL;
840         size_t size = 0;
841
842         if (ast_mutex_lock(&formatlock)) {
843                 ast_log(LOG_WARNING, "Unable to lock format list\n");
844                 return NULL;
845         }
846         /* set the O_TRUNC flag if and only if there is no O_APPEND specified */
847         if (!(flags & O_APPEND)) 
848                 myflags = O_TRUNC;
849         
850         myflags |= O_WRONLY | O_CREAT;
851
852         f = formats;
853         while(f) {
854                 if (exts_compare(f->exts, type)) {
855                         char *stringp=NULL;
856                         /* XXX Implement check XXX */
857                         ext = ast_strdupa(f->exts);
858                         stringp=ext;
859                         ext = strsep(&stringp, "|");
860                         fn = build_filename(filename, ext);
861                         fd = open(fn, flags | myflags, mode);
862
863                         if (option_cache_record_files && fd >= 0) {
864                                 close(fd);
865                                 /*
866                                    We touch orig_fn just as a place-holder so other things (like vmail) see the file is there.
867                                    What we are really doing is writing to record_cache_dir until we are done then we will mv the file into place.
868                                 */
869                                 orig_fn = ast_strdupa(fn); 
870                                 for (size=0;size<strlen(fn);size++) {
871                                         if (fn[size] == '/')
872                                                 fn[size] = '_';
873                                 }
874
875                                 size += (strlen(record_cache_dir) + 10);
876                                 buf = alloca(size);
877                                 memset(buf, 0, size);
878                                 snprintf(buf, size, "%s/%s", record_cache_dir, fn);
879                                 free(fn);
880                                 fn=buf;
881                                 fd = open(fn, flags | myflags, mode);
882                         }
883                         if (fd >= 0) {
884                                 errno = 0;
885                                 if ((fs = f->rewrite(fd, comment))) {
886                                         fs->trans = NULL;
887                                         fs->fmt = f;
888                                         fs->flags = flags;
889                                         fs->mode = mode;
890                                         if (option_cache_record_files) {
891                                                 fs->realfilename = build_filename(filename, ext);
892                                                 fs->filename = strdup(fn);
893                                         } else {
894                                                 fs->realfilename = NULL;
895                                                 fs->filename = strdup(filename);
896                                         }
897                                         fs->vfs = NULL;
898                                 } else {
899                                         ast_log(LOG_WARNING, "Unable to rewrite %s\n", fn);
900                                         close(fd);
901                                         unlink(fn);
902                                         if (orig_fn)
903                                                 unlink(orig_fn);
904                                 }
905                         } else if (errno != EEXIST) {
906                                 ast_log(LOG_WARNING, "Unable to open file %s: %s\n", fn, strerror(errno));
907                                 if (orig_fn)
908                                         unlink(orig_fn);
909                         }
910                         if (!buf) /* if buf != NULL then fn is already free and pointing to it */
911                                 free(fn);
912
913                         break;
914                 }
915                 f = f->next;
916         }
917         ast_mutex_unlock(&formatlock);
918         if (!f) 
919                 ast_log(LOG_WARNING, "No such format '%s'\n", type);
920         return fs;
921 }
922
923 char ast_waitstream(struct ast_channel *c, const char *breakon)
924 {
925         /* XXX Maybe I should just front-end ast_waitstream_full ? XXX */
926         int res;
927         struct ast_frame *fr;
928         if (!breakon) breakon = "";
929         while(c->stream) {
930                 res = ast_sched_wait(c->sched);
931                 if ((res < 0) && !c->timingfunc) {
932                         ast_stopstream(c);
933                         break;
934                 }
935                 if (res < 0)
936                         res = 1000;
937                 res = ast_waitfor(c, res);
938                 if (res < 0) {
939                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
940                         return res;
941                 } else if (res > 0) {
942                         fr = ast_read(c);
943                         if (!fr) {
944 #if 0
945                                 ast_log(LOG_DEBUG, "Got hung up\n");
946 #endif
947                                 return -1;
948                         }
949                         
950                         switch(fr->frametype) {
951                         case AST_FRAME_DTMF:
952                                 res = fr->subclass;
953                                 if (strchr(breakon, res)) {
954                                         ast_frfree(fr);
955                                         return res;
956                                 }
957                                 break;
958                         case AST_FRAME_CONTROL:
959                                 switch(fr->subclass) {
960                                 case AST_CONTROL_HANGUP:
961                                         ast_frfree(fr);
962                                         return -1;
963                                 case AST_CONTROL_RINGING:
964                                 case AST_CONTROL_ANSWER:
965                                         /* Unimportant */
966                                         break;
967                                 default:
968                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
969                                 }
970                         }
971                         /* Ignore */
972                         ast_frfree(fr);
973                 }
974                 ast_sched_runq(c->sched);
975         }
976         return (c->_softhangup ? -1 : 0);
977 }
978
979 char ast_waitstream_fr(struct ast_channel *c, const char *breakon, const char *forward, const char *rewind, int ms)
980 {
981         int res;
982         struct ast_frame *fr;
983         while(c->stream) {
984                 res = ast_sched_wait(c->sched);
985                 if ((res < 0) && !c->timingfunc) {
986                         ast_stopstream(c);
987                         break;
988                 }
989                 if (res < 0)
990                         res = 1000;
991                 res = ast_waitfor(c, res);
992                 if (res < 0) {
993                         ast_log(LOG_WARNING, "Select failed (%s)\n", strerror(errno));
994                         return res;
995                 } else
996                 if (res > 0) {
997                         fr = ast_read(c);
998                         if (!fr) {
999 #if 0
1000                                 ast_log(LOG_DEBUG, "Got hung up\n");
1001 #endif
1002                                 return -1;
1003                         }
1004                         
1005                         switch(fr->frametype) {
1006                         case AST_FRAME_DTMF:
1007                                 res = fr->subclass;
1008                                 if (strchr(forward,res)) {
1009                                         ast_stream_fastforward(c->stream, ms);
1010                                 } else if (strchr(rewind,res)) {
1011                                         ast_stream_rewind(c->stream, ms);
1012                                 } else if (strchr(breakon, res)) {
1013                                         ast_frfree(fr);
1014                                         return res;
1015                                 }                                       
1016                                 break;
1017                         case AST_FRAME_CONTROL:
1018                                 switch(fr->subclass) {
1019                                 case AST_CONTROL_HANGUP:
1020                                         ast_frfree(fr);
1021                                         return -1;
1022                                 case AST_CONTROL_RINGING:
1023                                 case AST_CONTROL_ANSWER:
1024                                         /* Unimportant */
1025                                         break;
1026                                 default:
1027                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1028                                 }
1029                         }
1030                         /* Ignore */
1031                         ast_frfree(fr);
1032                 } else
1033                         ast_sched_runq(c->sched);
1034         
1035                 
1036         }
1037         return (c->_softhangup ? -1 : 0);
1038 }
1039
1040 char ast_waitstream_full(struct ast_channel *c, const char *breakon, int audiofd, int cmdfd)
1041 {
1042         int res;
1043         int ms;
1044         int outfd;
1045         struct ast_frame *fr;
1046         struct ast_channel *rchan;
1047         
1048         while(c->stream) {
1049                 ms = ast_sched_wait(c->sched);
1050                 if ((ms < 0) && !c->timingfunc) {
1051                         ast_stopstream(c);
1052                         break;
1053                 }
1054                 if (ms < 0)
1055                         ms = 1000;
1056                 rchan = ast_waitfor_nandfds(&c, 1, &cmdfd, (cmdfd > -1) ? 1 : 0, NULL, &outfd, &ms);
1057                 if (!rchan && (outfd < 0) && (ms)) {
1058                         ast_log(LOG_WARNING, "Wait failed (%s)\n", strerror(errno));
1059                         return -1;
1060                 } else if (outfd > -1) {
1061                         /* The FD we were watching has something waiting */
1062                         return 1;
1063                 } else if (rchan) {
1064                         fr = ast_read(c);
1065                         if (!fr) {
1066 #if 0
1067                                 ast_log(LOG_DEBUG, "Got hung up\n");
1068 #endif
1069                                 return -1;
1070                         }
1071                         
1072                         switch(fr->frametype) {
1073                         case AST_FRAME_DTMF:
1074                                 res = fr->subclass;
1075                                 if (strchr(breakon, res)) {
1076                                         ast_frfree(fr);
1077                                         return res;
1078                                 }
1079                                 break;
1080                         case AST_FRAME_CONTROL:
1081                                 switch(fr->subclass) {
1082                                 case AST_CONTROL_HANGUP:
1083                                         ast_frfree(fr);
1084                                         return -1;
1085                                 case AST_CONTROL_RINGING:
1086                                 case AST_CONTROL_ANSWER:
1087                                         /* Unimportant */
1088                                         break;
1089                                 default:
1090                                         ast_log(LOG_WARNING, "Unexpected control subclass '%d'\n", fr->subclass);
1091                                 }
1092                         case AST_FRAME_VOICE:
1093                                 /* Write audio if appropriate */
1094                                 if (audiofd > -1)
1095                                         write(audiofd, fr->data, fr->datalen);
1096                         }
1097                         /* Ignore */
1098                         ast_frfree(fr);
1099                 }
1100                 ast_sched_runq(c->sched);
1101         
1102                 
1103         }
1104         return (c->_softhangup ? -1 : 0);
1105 }
1106
1107 static int show_file_formats(int fd, int argc, char *argv[])
1108 {
1109 #define FORMAT "%-10s %-10s %-20s\n"
1110 #define FORMAT2 "%-10s %-10s %-20s\n"
1111         struct ast_format *f;
1112         if (argc != 3)
1113                 return RESULT_SHOWUSAGE;
1114         ast_cli(fd, FORMAT, "Format", "Name", "Extensions");
1115                 
1116         if (ast_mutex_lock(&formatlock)) {
1117                 ast_log(LOG_WARNING, "Unable to lock format list\n");
1118                 return -1;
1119         }
1120
1121         f = formats;
1122         while(f) {
1123                 ast_cli(fd, FORMAT2, ast_getformatname(f->format), f->name, f->exts);
1124                 f = f->next;
1125         };
1126         ast_mutex_unlock(&formatlock);
1127         return RESULT_SUCCESS;
1128 }
1129
1130 struct ast_cli_entry show_file =
1131 {
1132         { "show", "file", "formats" },
1133         show_file_formats,
1134         "Displays file formats",
1135         "Usage: show file formats\n"
1136         "       displays currently registered file formats (if any)\n"
1137 };
1138
1139 int ast_file_init(void)
1140 {
1141         ast_cli_register(&show_file);
1142         return 0;
1143 }